diff --git a/.bazelrc b/.bazelrc index 0e8299f1d..9e0c82d02 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,2 @@ -build --cxxopt=-std=c++14 -build --host_cxxopt=-std=c++14 common --noenable_bzlmod +common --enable_workspace diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..ba7f754d0 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +7.4.0 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 diff --git a/.github/workflows/unwanted_deps.sh b/.github/workflows/unwanted_deps.sh new file mode 100755 index 000000000..b96951c41 --- /dev/null +++ b/.github/workflows/unwanted_deps.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# 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. + +# Script ran as part of Github CEL-Java CI to verify that the runtime jar does not contain generated cel protos from @cel_spec. + +runtime_deps="$(bazel query 'deps(//publish:cel_runtime)' --nohost_deps --noimplicit_deps --output graph | grep '@cel_spec')" + +if [[ ! -z $runtime_deps ]]; then + echo -e "Runtime contains unwanted @cel_spec dependency!\n" + echo "cel_spec dependency graph:" + echo -e "$runtime_deps" + exit 1 +fi + +exit 0 + diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 4cf231b27..35fe749fd 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -23,16 +23,22 @@ jobs: - run: echo "🐧 Job is running on a ${{ runner.os }} server!" - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." - name: Check out repository code - uses: actions/checkout@v3 - - name: Mount Bazel Cache - uses: actions/cache@v3 + uses: actions/checkout@v4 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 with: - path: "/home/runner/.cache/bazel" - key: bazelisk + # Avoid downloading Bazel every time. + bazelisk-cache: true + # Store build cache per workflow. + disk-cache: ${{ github.workflow }} + # Share repository cache between workflows. + repository-cache: true - name: Bazel Output Version run: bazelisk --version - name: Bazel Test # 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 + - name: Unwanted Dependencies + run: .github/workflows/unwanted_deps.sh - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/README.md b/README.md index 01e0a1450..89593e1a9 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.8.0 + 0.9.0 ``` **Gradle** ```gradle -implementation 'dev.cel:cel:0.8.0' +implementation 'dev.cel:cel:0.9.0' ``` Then run this example: diff --git a/WORKSPACE b/WORKSPACE index 97ecd141a..2c9bc18a2 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -43,19 +43,17 @@ load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() -RULES_JVM_EXTERNAL_TAG = "aa44247b3913da0da606e9c522313b6a9396a571" +RULES_JVM_EXTERNAL_TAG = "6.2" -RULES_JVM_EXTERNAL_SHA = "87378580865af690a78230e04eba1cd6d9c60d0db303ea129dc717705d711d9c" +RULES_JVM_EXTERNAL_SHA = "808cb5c30b5f70d12a2a745a29edc46728fd35fa195c1762a596b63ae9cebe05" -# rules_jvm_external as of 12/11/2023 http_archive( name = "rules_jvm_external", sha256 = RULES_JVM_EXTERNAL_SHA, strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, - url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, + url = "https://github.com/bazelbuild/rules_jvm_external/releases/download/%s/rules_jvm_external-%s.tar.gz" % (RULES_JVM_EXTERNAL_TAG, RULES_JVM_EXTERNAL_TAG), ) -load("@rules_jvm_external//:defs.bzl", "maven_install") load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") rules_jvm_external_deps() @@ -64,6 +62,8 @@ load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup() +load("@rules_jvm_external//:defs.bzl", "maven_install") + ANTLR4_VERSION = "4.13.2" # Important: there can only be one maven_install rule. Add new maven deps here. @@ -73,11 +73,11 @@ 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.33.0", + "com.google.errorprone:error_prone_annotations:2.36.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.protobuf:protobuf-java:4.28.3", + "com.google.protobuf:protobuf-java-util:4.28.3", "com.google.re2j:re2j:1.7", "com.google.testparameterinjector:test-parameter-injector:1.18", "com.google.truth.extensions:truth-java8-extension:1.4.4", @@ -96,9 +96,9 @@ maven_install( http_archive( name = "com_google_protobuf", - sha256 = "b2340aa47faf7ef10a0328190319d3f3bee1b24f426d4ce8f4253b6f27ce16db", - strip_prefix = "protobuf-28.2", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v28.2.tar.gz"], + sha256 = "7c3ebd7aaedd86fa5dc479a0fda803f602caaf78d8aff7ce83b89e1b8ae7442a", + strip_prefix = "protobuf-28.3", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v28.3.tar.gz"], ) # Required by com_google_protobuf @@ -148,12 +148,16 @@ http_archive( ) # cel-spec api/expr canonical protos +# v0.19.0 2024-12-02 +CEL_SPEC_COMMIT = "afa18f9bd5a83f5960ca06c1f9faea406ab34ccc" + http_archive( name = "cel_spec", - sha256 = "7136e18be8881153e05229fc040f8790b634af833d28efb102da00bad640b3ea", - strip_prefix = "cel-spec-e363cad95c4da033336f1350de063b16a3e36cd2", + sha256 = "3b74fc98b5efd10c53a220c694e80342db4e516151364dae97ec26dd308ce1c7", + strip_prefix = "cel-spec-" + CEL_SPEC_COMMIT, urls = [ - "https://github.com/google/cel-spec/archive/e363cad95c4da033336f1350de063b16a3e36cd2.tar.gz", + "https://github.com/google/cel-spec/archive/" + + CEL_SPEC_COMMIT + ".tar.gz", ], ) diff --git a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel index b6f170ee4..ab7e0349c 100644 --- a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel @@ -30,7 +30,7 @@ java_library( "//common:options", "//common/internal:env_visitor", "//common/internal:file_descriptor_converter", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "//common/values:cel_value_provider", "//compiler", diff --git a/bundle/src/main/java/dev/cel/bundle/CelImpl.java b/bundle/src/main/java/dev/cel/bundle/CelImpl.java index 317eeb49c..616a20e83 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelImpl.java +++ b/bundle/src/main/java/dev/cel/bundle/CelImpl.java @@ -39,9 +39,9 @@ import dev.cel.common.internal.EnvVisitable; import dev.cel.common.internal.EnvVisitor; import dev.cel.common.internal.FileDescriptorSetConverter; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; import dev.cel.common.values.CelValueProvider; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerBuilder; @@ -269,7 +269,7 @@ public CelBuilder addFunctionBindings(Iterable bi @Override public CelBuilder setResultType(CelType resultType) { checkNotNull(resultType); - return setProtoResultType(CelTypes.celTypeToType(resultType)); + return setProtoResultType(CelProtoTypes.celTypeToType(resultType)); } @Override diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel index be643cce7..17f852437 100644 --- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel @@ -10,7 +10,6 @@ java_library( testonly = True, srcs = glob(["*Test.java"]), deps = [ - "//:auto_value", "//:java_truth", "//bundle:cel", "//checker", @@ -18,13 +17,14 @@ java_library( "//checker:proto_type_mask", "//common", "//common:compiler_common", + "//common:error_codes", "//common:options", "//common:proto_ast", "//common/ast", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/testing", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:message_type_provider", "//common/types:type_providers", "//compiler", @@ -34,12 +34,11 @@ java_library( "//runtime", "//runtime:unknown_attributes", "@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", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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", - "@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", diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index db8f311e9..db4b60fe1 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -35,8 +35,6 @@ 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; @@ -63,6 +61,7 @@ import dev.cel.checker.ProtoTypeMask; import dev.cel.checker.TypeProvider; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelErrorCode; import dev.cel.common.CelIssue; import dev.cel.common.CelOptions; import dev.cel.common.CelProtoAbstractSyntaxTree; @@ -73,8 +72,8 @@ import dev.cel.common.ast.CelExpr.CelList; import dev.cel.common.testing.RepeatedTestProvider; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.EnumType; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; @@ -85,6 +84,8 @@ import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; import dev.cel.compiler.CelCompilerImpl; +import dev.cel.expr.conformance.proto2.Proto2ExtensionScopedMessage; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelParserImpl; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelAttribute; @@ -156,10 +157,10 @@ public final class CelImplTest { private static final CheckedExpr CHECKED_EXPR = CheckedExpr.newBuilder() .setExpr(EXPR) - .putTypeMap(1L, CelTypes.BOOL) - .putTypeMap(2L, CelTypes.BOOL) - .putTypeMap(3L, CelTypes.BOOL) - .putTypeMap(4L, CelTypes.BOOL) + .putTypeMap(1L, CelProtoTypes.BOOL) + .putTypeMap(2L, CelProtoTypes.BOOL) + .putTypeMap(3L, CelProtoTypes.BOOL) + .putTypeMap(4L, CelProtoTypes.BOOL) .putReferenceMap(2L, Reference.newBuilder().addOverloadId("logical_and").build()) .putReferenceMap(3L, Reference.newBuilder().addOverloadId("logical_not").build()) .build(); @@ -193,7 +194,7 @@ public void build_badFileDescriptorSet() { .addFile(AttributeContext.getDescriptor().getFile().toProto()) .build()) .setProtoResultType( - CelTypes.createMessage("google.rpc.context.AttributeContext.Resource")) + CelProtoTypes.createMessage("google.rpc.context.AttributeContext.Resource")) .build()); assertThat(e).hasMessageThat().contains("file descriptor set with unresolved proto file"); } @@ -219,7 +220,7 @@ public void check() throws Exception { public void compile(boolean useProtoResultType) throws Exception { CelBuilder celBuilder = standardCelBuilderWithMacros(); if (useProtoResultType) { - celBuilder.setProtoResultType(CelTypes.BOOL); + celBuilder.setProtoResultType(CelProtoTypes.BOOL); } else { celBuilder.setResultType(SimpleType.BOOL); } @@ -233,7 +234,7 @@ public void compile(boolean useProtoResultType) throws Exception { public void compile_resultTypeCheckFailure(boolean useProtoResultType) { CelBuilder celBuilder = standardCelBuilderWithMacros(); if (useProtoResultType) { - celBuilder.setProtoResultType(CelTypes.STRING); + celBuilder.setProtoResultType(CelProtoTypes.STRING); } else { celBuilder.setResultType(SimpleType.STRING); } @@ -257,7 +258,7 @@ public void compile_combinedTypeProvider() { .addProtoTypeMasks( ImmutableList.of(ProtoTypeMask.ofAllFields("google.rpc.context.AttributeContext"))) .addVar("condition", StructTypeReference.create("google.type.Expr")) - .setProtoResultType(CelTypes.BOOL) + .setProtoResultType(CelProtoTypes.BOOL) .build(); CelValidationResult result = cel.compile("type.Expr{expression: \"'hello'\"}.expression == condition.expression"); @@ -289,7 +290,8 @@ public void compile_customTypesWithAliasingCombinedProviders() throws Exception // However, the first type resolution from the alias to the qualified type name won't be // sufficient as future checks will expect the resolved alias to also be a type. TypeProvider customTypeProvider = - aliasingProvider(ImmutableMap.of("Condition", CelTypes.createMessage("google.type.Expr"))); + aliasingProvider( + ImmutableMap.of("Condition", CelProtoTypes.createMessage("google.type.Expr"))); // The registration of the aliasing TypeProvider and the google.type.Expr descriptor // ensures that once the alias is resolved, the additional details about the Expr type @@ -321,9 +323,9 @@ public void compile_customTypesWithAliasingSelfContainedProvider() throws Except aliasingProvider( ImmutableMap.of( "Condition", - CelTypes.createMessage("google.type.Expr"), + CelProtoTypes.createMessage("google.type.Expr"), "google.type.Expr", - CelTypes.createMessage("google.type.Expr"))); + CelProtoTypes.createMessage("google.type.Expr"))); // The registration of the aliasing TypeProvider and the google.type.Expr descriptor // ensures that once the alias is resolved, the additional details about the Expr type @@ -499,12 +501,14 @@ public void compile_overlappingVarsFailure() { .addDeclarations( Decl.newBuilder() .setName("variable") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.STRING)) .build()) .addDeclarations( Decl.newBuilder() .setName("variable") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.createList(CelTypes.STRING))) + .setIdent( + IdentDecl.newBuilder() + .setType(CelProtoTypes.createList(CelProtoTypes.STRING))) .build()) .setResultType(SimpleType.BOOL) .build(); @@ -528,7 +532,7 @@ public void program_withVars() throws Exception { .addDeclarations( Decl.newBuilder() .setName("variable") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.STRING)) .build()) .setResultType(SimpleType.BOOL) .build(); @@ -544,7 +548,7 @@ public void program_withCelValue() throws Exception { .addDeclarations( Decl.newBuilder() .setName("variable") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.STRING)) .build()) .setResultType(SimpleType.BOOL) .build(); @@ -654,11 +658,11 @@ public void program_withFunctions() throws Exception { ImmutableList.of( Decl.newBuilder() .setName("one") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.BOOL)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.BOOL)) .build(), Decl.newBuilder() .setName("two") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.BOOL)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.BOOL)) .build(), Decl.newBuilder() .setName("any") @@ -667,21 +671,21 @@ public void program_withFunctions() throws Exception { .addOverloads( Overload.newBuilder() .setOverloadId("any_bool") - .addParams(CelTypes.BOOL) - .setResultType(CelTypes.BOOL)) + .addParams(CelProtoTypes.BOOL) + .setResultType(CelProtoTypes.BOOL)) .addOverloads( Overload.newBuilder() .setOverloadId("any_bool_bool") - .addParams(CelTypes.BOOL) - .addParams(CelTypes.BOOL) - .setResultType(CelTypes.BOOL)) + .addParams(CelProtoTypes.BOOL) + .addParams(CelProtoTypes.BOOL) + .setResultType(CelProtoTypes.BOOL)) .addOverloads( Overload.newBuilder() .setOverloadId("any_bool_bool_bool") - .addParams(CelTypes.BOOL) - .addParams(CelTypes.BOOL) - .addParams(CelTypes.BOOL) - .setResultType(CelTypes.BOOL))) + .addParams(CelProtoTypes.BOOL) + .addParams(CelProtoTypes.BOOL) + .addParams(CelProtoTypes.BOOL) + .setResultType(CelProtoTypes.BOOL))) .build())) .addFunctionBindings(CelFunctionBinding.from("any_bool", Boolean.class, (arg) -> arg)) .addFunctionBindings( @@ -715,7 +719,7 @@ public void program_withThrowingFunction() throws Exception { .addOverloads( Overload.newBuilder() .setOverloadId("throws") - .setResultType(CelTypes.BOOL))) + .setResultType(CelProtoTypes.BOOL))) .build()) .addFunctionBindings( CelFunctionBinding.from( @@ -743,7 +747,7 @@ public void program_withThrowingFunctionShortcircuited() throws Exception { .addOverloads( Overload.newBuilder() .setOverloadId("throws") - .setResultType(CelTypes.BOOL))) + .setResultType(CelProtoTypes.BOOL))) .build()) .addFunctionBindings( CelFunctionBinding.from( @@ -959,7 +963,7 @@ public void program_protoActivation() throws Exception { .setIdent( IdentDecl.newBuilder() .setType( - CelTypes.createMessage( + CelProtoTypes.createMessage( "google.rpc.context.AttributeContext.Resource"))) .build()) .setResultType(SimpleType.STRING) @@ -1106,7 +1110,7 @@ public void program_customVarResolver() throws Exception { .addDeclarations( Decl.newBuilder() .setName("variable") - .setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING)) + .setIdent(IdentDecl.newBuilder().setType(CelProtoTypes.STRING)) .build()) .setResultType(SimpleType.BOOL) .build(); @@ -1149,7 +1153,7 @@ public void program_messageTypeAddedAsVarWithoutDescriptor_throwsHumanReadableEr String packageName = CheckedExpr.getDescriptor().getFile().getPackage(); Cel cel = standardCelBuilderWithMacros() - .addVar("parsedExprVar", CelTypes.createMessage(ParsedExpr.getDescriptor())) + .addVar("parsedExprVar", CelProtoTypes.createMessage(ParsedExpr.getDescriptor())) .build(); CelValidationException exception = assertThrows( @@ -1744,7 +1748,8 @@ public void programAdvanceEvaluation_boolOperatorMergeUnknownPriority() throws E UnknownContext.create( fromMap(ImmutableMap.of()), ImmutableList.of(CelAttributePattern.fromQualifiedIdentifier("unk"))))) - .isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("unk"))); + .isEqualTo( + CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("unk"), ImmutableSet.of(3L))); } @Test @@ -1817,13 +1822,13 @@ public void programAdvanceEvaluation_partialUnknownMessageFieldPropagates() thro .addMessageTypes(TestAllTypes.getDescriptor()) .addVar( "partialMessage1", - StructTypeReference.create("google.api.expr.test.v1.proto3.TestAllTypes")) + StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes")) .addVar( "partialMessage2", - StructTypeReference.create("google.api.expr.test.v1.proto3.TestAllTypes")) + StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes")) .setResultType( - StructTypeReference.create("google.api.expr.test.v1.proto3.NestedTestAllTypes")) - .setContainer("google.api.expr.test.v1.proto3") + StructTypeReference.create("cel.expr.conformance.proto3.NestedTestAllTypes")) + .setContainer("cel.expr.conformance.proto3") .addFunctionBindings() .build(); Program program = @@ -1926,6 +1931,107 @@ 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().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().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 + @TestParameters("{expression: 'string(123)'}") + @TestParameters("{expression: 'string(123u)'}") + @TestParameters("{expression: 'string(1.5)'}") + @TestParameters("{expression: 'string(\"foo\")'}") + @TestParameters("{expression: 'string(b\"foo\")'}") + @TestParameters("{expression: 'string(timestamp(100))'}") + @TestParameters("{expression: 'string(duration(\"1h\"))'}") + public void program_stringConversionDisabled_throws(String expression) throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .setOptions( + CelOptions.current() + .enableTimestampEpoch(true) + .enableStringConversion(false) + .build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile(expression).getAst(); + + CelEvaluationException e = + assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval()); + assertThat(e).hasMessageThat().contains("No matching overload for function 'string'"); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND); + } + + @Test + public void program_stringConcatenationDisabled_throws() throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableStringConcatenation(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("'foo' + 'bar'").getAst(); + + CelEvaluationException e = + assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval()); + assertThat(e).hasMessageThat().contains("No matching overload for function '_+_'"); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND); + } + + @Test + public void program_listConcatenationDisabled_throws() throws Exception { + Cel cel = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableListConcatenation(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("[1] + [2]").getAst(); + + CelEvaluationException e = + assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval()); + assertThat(e).hasMessageThat().contains("No matching overload for function '_+_'"); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.OVERLOAD_NOT_FOUND); + } + + @Test + public void program_comprehensionDisabled_throws() throws Exception { + Cel cel = + standardCelBuilderWithMacros() + .setOptions(CelOptions.current().enableComprehension(false).build()) + .build(); + CelAbstractSyntaxTree ast = cel.compile("['foo', 'bar'].map(x, x)").getAst(); + + CelEvaluationException e = + assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval()); + assertThat(e).hasMessageThat().contains("Iteration budget exceeded: 0"); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.ITERATION_BUDGET_EXCEEDED); + } + @Test public void toBuilder_isImmutable() { CelBuilder celBuilder = CelFactory.standardCelBuilder(); @@ -1953,7 +2059,7 @@ private static TypeProvider aliasingProvider(ImmutableMap typeAlia public @Nullable Type lookupType(String typeName) { Type alias = typeAliases.get(typeName); if (alias != null) { - return CelTypes.create(alias); + return CelProtoTypes.create(alias); } return null; } @@ -1966,7 +2072,7 @@ private static TypeProvider aliasingProvider(ImmutableMap typeAlia @Override public TypeProvider.@Nullable FieldType lookupFieldType(Type type, String fieldName) { if (typeAliases.containsKey(type.getMessageType())) { - return TypeProvider.FieldType.of(CelTypes.STRING); + return TypeProvider.FieldType.of(CelProtoTypes.STRING); } return null; } diff --git a/checker/BUILD.bazel b/checker/BUILD.bazel index 8add14f59..780bf53d0 100644 --- a/checker/BUILD.bazel +++ b/checker/BUILD.bazel @@ -53,3 +53,8 @@ java_library( name = "proto_expr_visitor", exports = ["//checker/src/main/java/dev/cel/checker:proto_expr_visitor"], ) + +java_library( + name = "standard_decl", + exports = ["//checker/src/main/java/dev/cel/checker:standard_decl"], +) diff --git a/checker/src/main/java/dev/cel/checker/BUILD.bazel b/checker/src/main/java/dev/cel/checker/BUILD.bazel index 05671f426..863bca193 100644 --- a/checker/src/main/java/dev/cel/checker/BUILD.bazel +++ b/checker/src/main/java/dev/cel/checker/BUILD.bazel @@ -30,7 +30,6 @@ CHECKER_LEGACY_ENV_SOURCES = [ "ExprChecker.java", "ExprVisitor.java", "InferenceContext.java", - "Standard.java", "TypeFormatter.java", "TypeProvider.java", "Types.java", @@ -50,7 +49,7 @@ java_library( "//common/annotations", "//common/internal:file_descriptor_converter", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", @@ -70,6 +69,7 @@ java_library( ":checker_builder", ":checker_legacy_environment", ":proto_type_mask", + ":standard_decl", ":type_provider_legacy_impl", "//:auto_value", "//common", @@ -81,7 +81,7 @@ java_library( "//common/internal:env_visitor", "//common/internal:errors", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:message_type_provider", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", @@ -99,6 +99,7 @@ java_library( deps = [ ":checker_legacy_environment", ":proto_type_mask", + ":standard_decl", "//common", "//common:compiler_common", "//common:options", @@ -134,7 +135,7 @@ java_library( "//common/annotations", "//common/ast", "//common/ast:expr_converter", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", @@ -152,7 +153,7 @@ java_library( "//:auto_value", "//common/annotations", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", @@ -168,6 +169,7 @@ java_library( ], deps = [ ":cel_ident_decl", + ":standard_decl", "//:auto_value", "//common", "//common:compiler_common", @@ -180,6 +182,7 @@ java_library( "//common/internal:errors", "//common/internal:file_descriptor_converter", "//common/types", + "//common/types:cel_proto_types", "//common/types:cel_types", "//common/types:type_providers", "//parser:macro", @@ -219,3 +222,22 @@ java_library( "//common:proto_ast", ], ) + +java_library( + name = "standard_decl", + srcs = [ + "CelStandardDeclarations.java", + ], + tags = [ + ], + deps = [ + ":cel_ident_decl", + "//common:compiler_common", + "//common/types", + "//common/types:cel_types", + "//common/types:type_providers", + "//parser:operator", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + ], +) diff --git a/checker/src/main/java/dev/cel/checker/CelCheckerBuilder.java b/checker/src/main/java/dev/cel/checker/CelCheckerBuilder.java index 53827c387..f0ec20698 100644 --- a/checker/src/main/java/dev/cel/checker/CelCheckerBuilder.java +++ b/checker/src/main/java/dev/cel/checker/CelCheckerBuilder.java @@ -152,6 +152,14 @@ public interface CelCheckerBuilder { @CanIgnoreReturnValue CelCheckerBuilder setStandardEnvironmentEnabled(boolean value); + /** + * Override the standard declarations for the type-checker. This can be used to subset the + * standard environment to only expose the desired declarations to the type-checker. {@link + * #setStandardEnvironmentEnabled(boolean)} must be set to false for this to take effect. + */ + @CanIgnoreReturnValue + CelCheckerBuilder setStandardDeclarations(CelStandardDeclarations standardDeclarations); + /** Adds one or more libraries for parsing and type-checking. */ @CanIgnoreReturnValue CelCheckerBuilder addLibraries(CelCheckerLibrary... libraries); diff --git a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java index a177b259d..539a432aa 100644 --- a/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java @@ -45,9 +45,9 @@ import dev.cel.common.internal.EnvVisitable; import dev.cel.common.internal.EnvVisitor; import dev.cel.common.internal.Errors; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.ProtoMessageTypeProvider; import java.util.ArrayList; import java.util.Arrays; @@ -78,6 +78,8 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable { private final CelTypeProvider celTypeProvider; private final boolean standardEnvironmentEnabled; + private final CelStandardDeclarations overriddenStandardDeclarations; + // Builder is mutable by design. APIs must make defensive copies in and out of this class. @SuppressWarnings("Immutable") private final Builder checkerBuilder; @@ -137,6 +139,8 @@ private Env getEnv(Errors errors) { Env env; if (standardEnvironmentEnabled) { env = Env.standard(errors, typeProvider, celOptions); + } else if (overriddenStandardDeclarations != null) { + env = Env.standard(overriddenStandardDeclarations, errors, typeProvider, celOptions); } else { env = Env.unconfigured(errors, typeProvider, celOptions); } @@ -165,6 +169,7 @@ public static final class Builder implements CelCheckerBuilder { private TypeProvider customTypeProvider; private CelTypeProvider celTypeProvider; private boolean standardEnvironmentEnabled; + private CelStandardDeclarations standardDeclarations; @Override public CelCheckerBuilder setOptions(CelOptions celOptions) { @@ -194,7 +199,7 @@ public CelCheckerBuilder addDeclarations(Iterable declarations) { CelIdentDecl.Builder identBuilder = CelIdentDecl.newBuilder() .setName(decl.getName()) - .setType(CelTypes.typeToCelType(decl.getIdent().getType())) + .setType(CelProtoTypes.typeToCelType(decl.getIdent().getType())) // Note: Setting doc and constant value exists for compatibility reason. This // should not be set by the users. .setDoc(decl.getIdent().getDoc()); @@ -273,7 +278,7 @@ public CelCheckerBuilder setResultType(CelType resultType) { @Override public CelCheckerBuilder setProtoResultType(Type resultType) { checkNotNull(resultType); - return setResultType(CelTypes.typeToCelType(resultType)); + return setResultType(CelProtoTypes.typeToCelType(resultType)); } @Override @@ -320,7 +325,13 @@ public CelCheckerBuilder addFileTypes(FileDescriptorSet fileDescriptorSet) { @Override public CelCheckerBuilder setStandardEnvironmentEnabled(boolean value) { - standardEnvironmentEnabled = value; + this.standardEnvironmentEnabled = value; + return this; + } + + @Override + public CelCheckerBuilder setStandardDeclarations(CelStandardDeclarations standardDeclarations) { + this.standardDeclarations = checkNotNull(standardDeclarations); return this; } @@ -372,6 +383,11 @@ ImmutableSet.Builder getCheckerLibraries() { @Override @CheckReturnValue public CelCheckerLegacyImpl build() { + if (standardEnvironmentEnabled && standardDeclarations != null) { + throw new IllegalArgumentException( + "setStandardEnvironmentEnabled must be set to false to override standard" + + " declarations."); + } // Add libraries, such as extensions celCheckerLibraries.build().forEach(celLibrary -> celLibrary.setCheckerOptions(this)); @@ -430,6 +446,7 @@ public CelCheckerLegacyImpl build() { legacyProvider, messageTypeProvider, standardEnvironmentEnabled, + standardDeclarations, this); } @@ -478,6 +495,7 @@ private CelCheckerLegacyImpl( TypeProvider typeProvider, CelTypeProvider celTypeProvider, boolean standardEnvironmentEnabled, + CelStandardDeclarations overriddenStandardDeclarations, Builder checkerBuilder) { this.celOptions = celOptions; this.container = container; @@ -487,6 +505,7 @@ private CelCheckerLegacyImpl( this.typeProvider = typeProvider; this.celTypeProvider = celTypeProvider; this.standardEnvironmentEnabled = standardEnvironmentEnabled; + this.overriddenStandardDeclarations = overriddenStandardDeclarations; this.checkerBuilder = new Builder(checkerBuilder); } diff --git a/checker/src/main/java/dev/cel/checker/CelIdentDecl.java b/checker/src/main/java/dev/cel/checker/CelIdentDecl.java index ac71523fe..60f747b77 100644 --- a/checker/src/main/java/dev/cel/checker/CelIdentDecl.java +++ b/checker/src/main/java/dev/cel/checker/CelIdentDecl.java @@ -23,8 +23,8 @@ import dev.cel.common.annotations.Internal; import dev.cel.common.ast.CelConstant; import dev.cel.common.ast.CelExprConverter; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import java.util.Optional; /** @@ -57,7 +57,7 @@ public static Decl celIdentToDecl(CelIdentDecl identDecl) { IdentDecl.Builder identBuilder = IdentDecl.newBuilder() .setDoc(identDecl.doc()) - .setType(CelTypes.celTypeToType(identDecl.type())); + .setType(CelProtoTypes.celTypeToType(identDecl.type())); if (identDecl.constant().isPresent()) { identBuilder.setValue(CelExprConverter.celConstantToExprConstant(identDecl.constant().get())); } diff --git a/checker/src/main/java/dev/cel/checker/CelStandardDeclarations.java b/checker/src/main/java/dev/cel/checker/CelStandardDeclarations.java new file mode 100644 index 000000000..8a84c2a48 --- /dev/null +++ b/checker/src/main/java/dev/cel/checker/CelStandardDeclarations.java @@ -0,0 +1,1771 @@ +// 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.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static java.util.Arrays.stream; + +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.Immutable; +import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOverloadDecl; +import dev.cel.common.types.CelType; +import dev.cel.common.types.CelTypes; +import dev.cel.common.types.ListType; +import dev.cel.common.types.MapType; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.TypeParamType; +import dev.cel.common.types.TypeType; +import dev.cel.parser.Operator; + +/** + * Standard declarations for CEL. + * + *

Refer to CEL + * Specification for comprehensive listing of functions and identifiers included in the standard + * environment. + */ +@Immutable +public final class CelStandardDeclarations { + // Some shortcuts we use when building declarations. + private static final TypeParamType TYPE_PARAM_A = TypeParamType.create("A"); + private static final ListType LIST_OF_A = ListType.create(TYPE_PARAM_A); + private static final TypeParamType TYPE_PARAM_B = TypeParamType.create("B"); + private static final MapType MAP_OF_AB = MapType.create(TYPE_PARAM_A, TYPE_PARAM_B); + + private static final ImmutableSet DEPRECATED_STANDARD_FUNCTIONS = + ImmutableSet.of( + CelFunctionDecl.newFunctionDeclaration( + Operator.OLD_NOT_STRICTLY_FALSE.getFunction(), + CelOverloadDecl.newGlobalOverload( + "not_strictly_false", + "false if argument is false, true otherwise (including errors and unknowns)", + SimpleType.BOOL, + SimpleType.BOOL)), + CelFunctionDecl.newFunctionDeclaration( + Operator.OLD_IN.getFunction(), + CelOverloadDecl.newGlobalOverload( + "in_list", "list membership", SimpleType.BOOL, TYPE_PARAM_A, LIST_OF_A), + CelOverloadDecl.newGlobalOverload( + "in_map", "map key membership", SimpleType.BOOL, TYPE_PARAM_A, MAP_OF_AB))); + + private final ImmutableSet celFunctionDecls; + private final ImmutableSet celIdentDecls; + + /** Enumeration of Standard Functions. */ + enum StandardFunction { + // Internal (rewritten by macro) + IN(Operator.IN, Overload.InternalOperator.IN_LIST, Overload.InternalOperator.IN_MAP), + NOT_STRICTLY_FALSE(Operator.NOT_STRICTLY_FALSE, Overload.InternalOperator.NOT_STRICTLY_FALSE), + TYPE("type", Overload.InternalOperator.TYPE), + + // Booleans + CONDITIONAL(Operator.CONDITIONAL, Overload.BooleanOperator.CONDITIONAL), + LOGICAL_NOT(Operator.LOGICAL_NOT, Overload.BooleanOperator.LOGICAL_NOT), + LOGICAL_OR(Operator.LOGICAL_OR, Overload.BooleanOperator.LOGICAL_OR), + LOGICAL_AND(Operator.LOGICAL_AND, Overload.BooleanOperator.LOGICAL_AND), + + // Relations + EQUALS(Operator.EQUALS, Overload.Relation.EQUALS), + NOT_EQUALS(Operator.NOT_EQUALS, Overload.Relation.NOT_EQUALS), + + // Arithmetic + ADD( + Operator.ADD, + Overload.Arithmetic.ADD_INT64, + Overload.Arithmetic.ADD_UINT64, + Overload.Arithmetic.ADD_DOUBLE, + Overload.Arithmetic.ADD_STRING, + Overload.Arithmetic.ADD_BYTES, + Overload.Arithmetic.ADD_LIST, + Overload.Arithmetic.ADD_TIMESTAMP_DURATION, + Overload.Arithmetic.ADD_DURATION_TIMESTAMP, + Overload.Arithmetic.ADD_DURATION_DURATION), + SUBTRACT( + Operator.SUBTRACT, + Overload.Arithmetic.SUBTRACT_INT64, + Overload.Arithmetic.SUBTRACT_UINT64, + Overload.Arithmetic.SUBTRACT_DOUBLE, + Overload.Arithmetic.SUBTRACT_TIMESTAMP_TIMESTAMP, + Overload.Arithmetic.SUBTRACT_TIMESTAMP_DURATION, + Overload.Arithmetic.SUBTRACT_DURATION_DURATION), + MULTIPLY( + Operator.MULTIPLY, + Overload.Arithmetic.MULTIPLY_INT64, + Overload.Arithmetic.MULTIPLY_UINT64, + Overload.Arithmetic.MULTIPLY_DOUBLE), + DIVIDE( + Operator.DIVIDE, + Overload.Arithmetic.DIVIDE_INT64, + Overload.Arithmetic.DIVIDE_UINT64, + Overload.Arithmetic.DIVIDE_DOUBLE), + MODULO(Operator.MODULO, Overload.Arithmetic.MODULO_INT64, Overload.Arithmetic.MODULO_UINT64), + + NEGATE(Operator.NEGATE, Overload.Arithmetic.NEGATE_INT64, Overload.Arithmetic.NEGATE_DOUBLE), + + // Index + INDEX(Operator.INDEX, Overload.Index.INDEX_LIST, Overload.Index.INDEX_MAP), + + // Size + SIZE( + "size", + Overload.Size.SIZE_STRING, + Overload.Size.SIZE_BYTES, + Overload.Size.SIZE_LIST, + Overload.Size.SIZE_MAP, + Overload.Size.STRING_SIZE, + Overload.Size.BYTES_SIZE, + Overload.Size.LIST_SIZE, + Overload.Size.MAP_SIZE), + + // Conversions + INT( + "int", + Overload.Conversions.INT64_TO_INT64, + Overload.Conversions.UINT64_TO_INT64, + Overload.Conversions.DOUBLE_TO_INT64, + Overload.Conversions.STRING_TO_INT64, + Overload.Conversions.TIMESTAMP_TO_INT64), + UINT( + "uint", + Overload.Conversions.UINT64_TO_UINT64, + Overload.Conversions.INT64_TO_UINT64, + Overload.Conversions.DOUBLE_TO_UINT64, + Overload.Conversions.STRING_TO_UINT64), + DOUBLE( + "double", + Overload.Conversions.DOUBLE_TO_DOUBLE, + Overload.Conversions.INT64_TO_DOUBLE, + Overload.Conversions.UINT64_TO_DOUBLE, + Overload.Conversions.STRING_TO_DOUBLE), + STRING( + "string", + Overload.Conversions.STRING_TO_STRING, + Overload.Conversions.INT64_TO_STRING, + Overload.Conversions.UINT64_TO_STRING, + Overload.Conversions.DOUBLE_TO_STRING, + Overload.Conversions.BYTES_TO_STRING, + Overload.Conversions.TIMESTAMP_TO_STRING, + Overload.Conversions.DURATION_TO_STRING), + BYTES("bytes", Overload.Conversions.BYTES_TO_BYTES, Overload.Conversions.STRING_TO_BYTES), + DYN("dyn", Overload.Conversions.TO_DYN), + DURATION( + "duration", + Overload.Conversions.DURATION_TO_DURATION, + Overload.Conversions.STRING_TO_DURATION), + TIMESTAMP( + "timestamp", + Overload.Conversions.STRING_TO_TIMESTAMP, + Overload.Conversions.TIMESTAMP_TO_TIMESTAMP, + Overload.Conversions.INT64_TO_TIMESTAMP), + BOOL("bool", Overload.Conversions.BOOL_TO_BOOL, Overload.Conversions.STRING_TO_BOOL), + + // String matchers + MATCHES("matches", Overload.StringMatchers.MATCHES, Overload.StringMatchers.MATCHES_STRING), + CONTAINS("contains", Overload.StringMatchers.CONTAINS_STRING), + ENDS_WITH("endsWith", Overload.StringMatchers.ENDS_WITH_STRING), + STARTS_WITH("startsWith", Overload.StringMatchers.STARTS_WITH_STRING), + + // Date/time operations + GET_FULL_YEAR( + "getFullYear", + Overload.DateTime.TIMESTAMP_TO_YEAR, + Overload.DateTime.TIMESTAMP_TO_YEAR_WITH_TZ), + GET_MONTH( + "getMonth", + Overload.DateTime.TIMESTAMP_TO_MONTH, + Overload.DateTime.TIMESTAMP_TO_MONTH_WITH_TZ), + GET_DAY_OF_YEAR( + "getDayOfYear", + Overload.DateTime.TIMESTAMP_TO_DAY_OF_YEAR, + Overload.DateTime.TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ), + GET_DAY_OF_MONTH( + "getDayOfMonth", + Overload.DateTime.TIMESTAMP_TO_DAY_OF_MONTH, + Overload.DateTime.TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ), + GET_DATE( + "getDate", + Overload.DateTime.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED, + Overload.DateTime.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ), + GET_DAY_OF_WEEK( + "getDayOfWeek", + Overload.DateTime.TIMESTAMP_TO_DAY_OF_WEEK, + Overload.DateTime.TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ), + GET_HOURS( + "getHours", + Overload.DateTime.TIMESTAMP_TO_HOURS, + Overload.DateTime.TIMESTAMP_TO_HOURS_WITH_TZ, + Overload.DateTime.DURATION_TO_HOURS), + GET_MINUTES( + "getMinutes", + Overload.DateTime.TIMESTAMP_TO_MINUTES, + Overload.DateTime.TIMESTAMP_TO_MINUTES_WITH_TZ, + Overload.DateTime.DURATION_TO_MINUTES), + GET_SECONDS( + "getSeconds", + Overload.DateTime.TIMESTAMP_TO_SECONDS, + Overload.DateTime.TIMESTAMP_TO_SECONDS_WITH_TZ, + Overload.DateTime.DURATION_TO_SECONDS), + GET_MILLISECONDS( + "getMilliseconds", + Overload.DateTime.TIMESTAMP_TO_MILLISECONDS, + Overload.DateTime.TIMESTAMP_TO_MILLISECONDS_WITH_TZ, + Overload.DateTime.DURATION_TO_MILLISECONDS), + + // Comparisons + LESS( + Operator.LESS, + Overload.Comparison.LESS_BOOL, + Overload.Comparison.LESS_INT64, + Overload.Comparison.LESS_UINT64, + Overload.Comparison.LESS_DOUBLE, + Overload.Comparison.LESS_STRING, + Overload.Comparison.LESS_BYTES, + Overload.Comparison.LESS_TIMESTAMP, + Overload.Comparison.LESS_DURATION, + Overload.Comparison.LESS_INT64_UINT64, + Overload.Comparison.LESS_UINT64_INT64, + Overload.Comparison.LESS_INT64_DOUBLE, + Overload.Comparison.LESS_DOUBLE_INT64, + Overload.Comparison.LESS_UINT64_DOUBLE, + Overload.Comparison.LESS_DOUBLE_UINT64), + LESS_EQUALS( + Operator.LESS_EQUALS, + Overload.Comparison.LESS_EQUALS_BOOL, + Overload.Comparison.LESS_EQUALS_INT64, + Overload.Comparison.LESS_EQUALS_UINT64, + Overload.Comparison.LESS_EQUALS_DOUBLE, + Overload.Comparison.LESS_EQUALS_STRING, + Overload.Comparison.LESS_EQUALS_BYTES, + Overload.Comparison.LESS_EQUALS_TIMESTAMP, + Overload.Comparison.LESS_EQUALS_DURATION, + Overload.Comparison.LESS_EQUALS_INT64_UINT64, + Overload.Comparison.LESS_EQUALS_UINT64_INT64, + Overload.Comparison.LESS_EQUALS_INT64_DOUBLE, + Overload.Comparison.LESS_EQUALS_DOUBLE_INT64, + Overload.Comparison.LESS_EQUALS_UINT64_DOUBLE, + Overload.Comparison.LESS_EQUALS_DOUBLE_UINT64), + GREATER( + Operator.GREATER, + Overload.Comparison.GREATER_BOOL, + Overload.Comparison.GREATER_INT64, + Overload.Comparison.GREATER_UINT64, + Overload.Comparison.GREATER_DOUBLE, + Overload.Comparison.GREATER_STRING, + Overload.Comparison.GREATER_BYTES, + Overload.Comparison.GREATER_TIMESTAMP, + Overload.Comparison.GREATER_DURATION, + Overload.Comparison.GREATER_INT64_UINT64, + Overload.Comparison.GREATER_UINT64_INT64, + Overload.Comparison.GREATER_INT64_DOUBLE, + Overload.Comparison.GREATER_DOUBLE_INT64, + Overload.Comparison.GREATER_UINT64_DOUBLE, + Overload.Comparison.GREATER_DOUBLE_UINT64), + GREATER_EQUALS( + Operator.GREATER_EQUALS, + Overload.Comparison.GREATER_EQUALS_BOOL, + Overload.Comparison.GREATER_EQUALS_INT64, + Overload.Comparison.GREATER_EQUALS_UINT64, + Overload.Comparison.GREATER_EQUALS_DOUBLE, + Overload.Comparison.GREATER_EQUALS_STRING, + Overload.Comparison.GREATER_EQUALS_BYTES, + Overload.Comparison.GREATER_EQUALS_TIMESTAMP, + Overload.Comparison.GREATER_EQUALS_DURATION, + Overload.Comparison.GREATER_EQUALS_INT64_UINT64, + Overload.Comparison.GREATER_EQUALS_UINT64_INT64, + Overload.Comparison.GREATER_EQUALS_INT64_DOUBLE, + Overload.Comparison.GREATER_EQUALS_DOUBLE_INT64, + Overload.Comparison.GREATER_EQUALS_UINT64_DOUBLE, + Overload.Comparison.GREATER_EQUALS_DOUBLE_UINT64), + ; + + private final String functionName; + private final CelFunctionDecl celFunctionDecl; + private final ImmutableSet standardOverloads; + + /** Container class for CEL standard function overloads. */ + public static final class Overload { + + /** + * Overloads for internal functions that may have been rewritten by macros (ex: @in), or those + * used for special purposes (comprehensions, type denotations etc). + */ + public enum InternalOperator implements StandardOverload { + IN_LIST( + CelOverloadDecl.newGlobalOverload( + "in_list", "list membership", SimpleType.BOOL, TYPE_PARAM_A, LIST_OF_A)), + IN_MAP( + CelOverloadDecl.newGlobalOverload( + "in_map", "map key membership", SimpleType.BOOL, TYPE_PARAM_A, MAP_OF_AB)), + NOT_STRICTLY_FALSE( + CelOverloadDecl.newGlobalOverload( + "not_strictly_false", + "false if argument is false, true otherwise (including errors and unknowns)", + SimpleType.BOOL, + SimpleType.BOOL)), + TYPE( + CelOverloadDecl.newGlobalOverload( + "type", "returns type of value", TypeType.create(TYPE_PARAM_A), TYPE_PARAM_A)), + ; + + private final CelOverloadDecl celOverloadDecl; + + InternalOperator(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for logical operators that return a bool as a result. */ + public enum BooleanOperator implements StandardOverload { + CONDITIONAL( + CelOverloadDecl.newGlobalOverload( + "conditional", + "conditional", + TYPE_PARAM_A, + SimpleType.BOOL, + TYPE_PARAM_A, + TYPE_PARAM_A)), + LOGICAL_NOT( + CelOverloadDecl.newGlobalOverload( + "logical_not", "logical not", SimpleType.BOOL, SimpleType.BOOL)), + LOGICAL_OR( + CelOverloadDecl.newGlobalOverload( + "logical_or", "logical or", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL)), + LOGICAL_AND( + CelOverloadDecl.newGlobalOverload( + "logical_and", "logical_and", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL)), + ; + + private final CelOverloadDecl celOverloadDecl; + + BooleanOperator(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for functions that test relations. */ + public enum Relation implements StandardOverload { + EQUALS( + CelOverloadDecl.newGlobalOverload( + "equals", "equality", SimpleType.BOOL, TYPE_PARAM_A, TYPE_PARAM_A)), + NOT_EQUALS( + CelOverloadDecl.newGlobalOverload( + "not_equals", "inequality", SimpleType.BOOL, TYPE_PARAM_A, TYPE_PARAM_A)), + ; + private final CelOverloadDecl celOverloadDecl; + + Relation(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for performing arithmetic operations. */ + public enum Arithmetic implements StandardOverload { + + // Add + ADD_STRING( + CelOverloadDecl.newGlobalOverload( + "add_string", + "string concatenation", + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING)), + ADD_BYTES( + CelOverloadDecl.newGlobalOverload( + "add_bytes", + "bytes concatenation", + SimpleType.BYTES, + SimpleType.BYTES, + SimpleType.BYTES)), + ADD_LIST( + CelOverloadDecl.newGlobalOverload( + "add_list", "list concatenation", LIST_OF_A, LIST_OF_A, LIST_OF_A)), + ADD_TIMESTAMP_DURATION( + CelOverloadDecl.newGlobalOverload( + "add_timestamp_duration", + "arithmetic", + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP, + SimpleType.DURATION)), + ADD_DURATION_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "add_duration_timestamp", + "arithmetic", + SimpleType.TIMESTAMP, + SimpleType.DURATION, + SimpleType.TIMESTAMP)), + ADD_DURATION_DURATION( + CelOverloadDecl.newGlobalOverload( + "add_duration_duration", + "arithmetic", + SimpleType.DURATION, + SimpleType.DURATION, + SimpleType.DURATION)), + ADD_INT64( + CelOverloadDecl.newGlobalOverload( + "add_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT)), + ADD_UINT64( + CelOverloadDecl.newGlobalOverload( + "add_uint64", "arithmetic", SimpleType.UINT, SimpleType.UINT, SimpleType.UINT)), + ADD_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "add_double", + "arithmetic", + SimpleType.DOUBLE, + SimpleType.DOUBLE, + SimpleType.DOUBLE)), + + // Subtract + SUBTRACT_INT64( + CelOverloadDecl.newGlobalOverload( + "subtract_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT)), + SUBTRACT_UINT64( + CelOverloadDecl.newGlobalOverload( + "subtract_uint64", + "arithmetic", + SimpleType.UINT, + SimpleType.UINT, + SimpleType.UINT)), + SUBTRACT_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "subtract_double", + "arithmetic", + SimpleType.DOUBLE, + SimpleType.DOUBLE, + SimpleType.DOUBLE)), + SUBTRACT_TIMESTAMP_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "subtract_timestamp_timestamp", + "arithmetic", + SimpleType.DURATION, + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP)), + SUBTRACT_TIMESTAMP_DURATION( + CelOverloadDecl.newGlobalOverload( + "subtract_timestamp_duration", + "arithmetic", + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP, + SimpleType.DURATION)), + SUBTRACT_DURATION_DURATION( + CelOverloadDecl.newGlobalOverload( + "subtract_duration_duration", + "arithmetic", + SimpleType.DURATION, + SimpleType.DURATION, + SimpleType.DURATION)), + + // Multiply + MULTIPLY_INT64( + CelOverloadDecl.newGlobalOverload( + "multiply_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT)), + MULTIPLY_UINT64( + CelOverloadDecl.newGlobalOverload( + "multiply_uint64", + "arithmetic", + SimpleType.UINT, + SimpleType.UINT, + SimpleType.UINT)), + MULTIPLY_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "multiply_double", + "arithmetic", + SimpleType.DOUBLE, + SimpleType.DOUBLE, + SimpleType.DOUBLE)), + + // Divide + DIVIDE_INT64( + CelOverloadDecl.newGlobalOverload( + "divide_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT)), + DIVIDE_UINT64( + CelOverloadDecl.newGlobalOverload( + "divide_uint64", "arithmetic", SimpleType.UINT, SimpleType.UINT, SimpleType.UINT)), + DIVIDE_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "divide_double", + "arithmetic", + SimpleType.DOUBLE, + SimpleType.DOUBLE, + SimpleType.DOUBLE)), + + // Modulo + MODULO_INT64( + CelOverloadDecl.newGlobalOverload( + "modulo_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT)), + MODULO_UINT64( + CelOverloadDecl.newGlobalOverload( + "modulo_uint64", "arithmetic", SimpleType.UINT, SimpleType.UINT, SimpleType.UINT)), + NEGATE_INT64( + CelOverloadDecl.newGlobalOverload( + "negate_int64", "negation", SimpleType.INT, SimpleType.INT)), + NEGATE_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "negate_double", "negation", SimpleType.DOUBLE, SimpleType.DOUBLE)), + ; + private final CelOverloadDecl celOverloadDecl; + + Arithmetic(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for indexing a list or a map. */ + public enum Index implements StandardOverload { + INDEX_LIST( + CelOverloadDecl.newGlobalOverload( + "index_list", "list indexing", TYPE_PARAM_A, LIST_OF_A, SimpleType.INT)), + INDEX_MAP( + CelOverloadDecl.newGlobalOverload( + "index_map", "map indexing", TYPE_PARAM_B, MAP_OF_AB, TYPE_PARAM_A)), + ; + private final CelOverloadDecl celOverloadDecl; + + Index(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for retrieving the size of a literal or a collection. */ + public enum Size implements StandardOverload { + SIZE_STRING( + CelOverloadDecl.newGlobalOverload( + "size_string", "string length", SimpleType.INT, SimpleType.STRING)), + SIZE_BYTES( + CelOverloadDecl.newGlobalOverload( + "size_bytes", "bytes length", SimpleType.INT, SimpleType.BYTES)), + SIZE_LIST( + CelOverloadDecl.newGlobalOverload("size_list", "list size", SimpleType.INT, LIST_OF_A)), + SIZE_MAP( + CelOverloadDecl.newGlobalOverload("size_map", "map size", SimpleType.INT, MAP_OF_AB)), + STRING_SIZE( + CelOverloadDecl.newMemberOverload( + "string_size", "string length", SimpleType.INT, SimpleType.STRING)), + BYTES_SIZE( + CelOverloadDecl.newMemberOverload( + "bytes_size", "bytes length", SimpleType.INT, SimpleType.BYTES)), + LIST_SIZE( + CelOverloadDecl.newMemberOverload("list_size", "list size", SimpleType.INT, LIST_OF_A)), + MAP_SIZE( + CelOverloadDecl.newMemberOverload("map_size", "map size", SimpleType.INT, MAP_OF_AB)), + ; + + private final CelOverloadDecl celOverloadDecl; + + Size(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for performing type conversions. */ + public enum Conversions implements StandardOverload { + // Bool conversions + BOOL_TO_BOOL( + CelOverloadDecl.newGlobalOverload( + "bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL)), + STRING_TO_BOOL( + CelOverloadDecl.newGlobalOverload( + "string_to_bool", "type conversion", SimpleType.BOOL, SimpleType.STRING)), + + // Int conversions + INT64_TO_INT64( + CelOverloadDecl.newGlobalOverload( + "int64_to_int64", "type conversion (identity)", SimpleType.INT, SimpleType.INT)), + UINT64_TO_INT64( + CelOverloadDecl.newGlobalOverload( + "uint64_to_int64", "type conversion", SimpleType.INT, SimpleType.UINT)), + DOUBLE_TO_INT64( + CelOverloadDecl.newGlobalOverload( + "double_to_int64", "type conversion", SimpleType.INT, SimpleType.DOUBLE)), + STRING_TO_INT64( + CelOverloadDecl.newGlobalOverload( + "string_to_int64", "type conversion", SimpleType.INT, SimpleType.STRING)), + TIMESTAMP_TO_INT64( + CelOverloadDecl.newGlobalOverload( + "timestamp_to_int64", + "Convert timestamp to int64 in seconds since Unix epoch.", + SimpleType.INT, + SimpleType.TIMESTAMP)), + // Uint conversions + UINT64_TO_UINT64( + CelOverloadDecl.newGlobalOverload( + "uint64_to_uint64", + "type conversion (identity)", + SimpleType.UINT, + SimpleType.UINT)), + INT64_TO_UINT64( + CelOverloadDecl.newGlobalOverload( + "int64_to_uint64", "type conversion", SimpleType.UINT, SimpleType.INT)), + DOUBLE_TO_UINT64( + CelOverloadDecl.newGlobalOverload( + "double_to_uint64", "type conversion", SimpleType.UINT, SimpleType.DOUBLE)), + STRING_TO_UINT64( + CelOverloadDecl.newGlobalOverload( + "string_to_uint64", "type conversion", SimpleType.UINT, SimpleType.STRING)), + // Double conversions + DOUBLE_TO_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "double_to_double", + "type conversion (identity)", + SimpleType.DOUBLE, + SimpleType.DOUBLE)), + INT64_TO_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "int64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.INT)), + UINT64_TO_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "uint64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.UINT)), + STRING_TO_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "string_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.STRING)), + // String conversions + STRING_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "string_to_string", + "type conversion (identity)", + SimpleType.STRING, + SimpleType.STRING)), + INT64_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "int64_to_string", "type conversion", SimpleType.STRING, SimpleType.INT)), + UINT64_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "uint64_to_string", "type conversion", SimpleType.STRING, SimpleType.UINT)), + DOUBLE_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "double_to_string", "type conversion", SimpleType.STRING, SimpleType.DOUBLE)), + BYTES_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "bytes_to_string", "type conversion", SimpleType.STRING, SimpleType.BYTES)), + TIMESTAMP_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "timestamp_to_string", "type_conversion", SimpleType.STRING, SimpleType.TIMESTAMP)), + DURATION_TO_STRING( + CelOverloadDecl.newGlobalOverload( + "duration_to_string", "type_conversion", SimpleType.STRING, SimpleType.DURATION)), + // Bytes conversions + BYTES_TO_BYTES( + CelOverloadDecl.newGlobalOverload( + "bytes_to_bytes", + "type conversion (identity)", + SimpleType.BYTES, + SimpleType.BYTES)), + STRING_TO_BYTES( + CelOverloadDecl.newGlobalOverload( + "string_to_bytes", "type conversion", SimpleType.BYTES, SimpleType.STRING)), + // Duration conversions + DURATION_TO_DURATION( + CelOverloadDecl.newGlobalOverload( + "duration_to_duration", + "type conversion (identity)", + SimpleType.DURATION, + SimpleType.DURATION)), + STRING_TO_DURATION( + CelOverloadDecl.newGlobalOverload( + "string_to_duration", + "type conversion, duration should be end with \"s\", which stands for seconds", + SimpleType.DURATION, + SimpleType.STRING)), + // Timestamp conversions + STRING_TO_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "string_to_timestamp", + "Type conversion of strings to timestamps according to RFC3339. Example:" + + " \"1972-01-01T10:00:20.021-05:00\".", + SimpleType.TIMESTAMP, + SimpleType.STRING)), + TIMESTAMP_TO_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "timestamp_to_timestamp", + "type conversion (identity)", + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP)), + INT64_TO_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "int64_to_timestamp", + "Type conversion of integers as Unix epoch seconds to timestamps.", + SimpleType.TIMESTAMP, + SimpleType.INT)), + + // Dyn conversions + TO_DYN( + CelOverloadDecl.newGlobalOverload( + "to_dyn", "type conversion", SimpleType.DYN, TYPE_PARAM_A)), + ; + private final CelOverloadDecl celOverloadDecl; + + Conversions(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** + * Overloads for functions performing string matching, such as regular expressions or contains + * check. + */ + public enum StringMatchers implements StandardOverload { + MATCHES( + CelOverloadDecl.newGlobalOverload( + "matches", + "matches first argument against regular expression in second argument", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING)), + + MATCHES_STRING( + CelOverloadDecl.newMemberOverload( + "matches_string", + "matches the self argument against regular expression in first argument", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING)), + + CONTAINS_STRING( + CelOverloadDecl.newMemberOverload( + "contains_string", + "tests whether the string operand contains the substring", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING)), + + ENDS_WITH_STRING( + CelOverloadDecl.newMemberOverload( + "ends_with_string", + "tests whether the string operand ends with the suffix argument", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING)), + + STARTS_WITH_STRING( + CelOverloadDecl.newMemberOverload( + "starts_with_string", + "tests whether the string operand starts with the prefix argument", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING)), + ; + private final CelOverloadDecl celOverloadDecl; + + StringMatchers(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for functions performing date/time operations. */ + public enum DateTime implements StandardOverload { + TIMESTAMP_TO_YEAR( + CelOverloadDecl.newMemberOverload( + "timestamp_to_year", + "get year from the date in UTC", + SimpleType.INT, + SimpleType.TIMESTAMP)), + TIMESTAMP_TO_YEAR_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_year_with_tz", + "get year from the date with timezone", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_MONTH( + CelOverloadDecl.newMemberOverload( + "timestamp_to_month", + "get month from the date in UTC, 0-11", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_MONTH_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_month_with_tz", + "get month from the date with timezone, 0-11", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_DAY_OF_YEAR( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_year", + "get day of year from the date in UTC, zero-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_year_with_tz", + "get day of year from the date with timezone, zero-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_DAY_OF_MONTH( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_month", + "get day of month from the date in UTC, zero-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_month_with_tz", + "get day of month from the date with timezone, zero-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_DAY_OF_MONTH_1_BASED( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_month_1_based", + "get day of month from the date in UTC, one-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP)), + TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_month_1_based_with_tz", + "get day of month from the date with timezone, one-based indexing", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_DAY_OF_WEEK( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_week", + "get day of week from the date in UTC, zero-based, zero for Sunday", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_day_of_week_with_tz", + "get day of week from the date with timezone, zero-based, zero for Sunday", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + TIMESTAMP_TO_HOURS( + CelOverloadDecl.newMemberOverload( + "timestamp_to_hours", + "get hours from the date in UTC, 0-23", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_HOURS_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_hours_with_tz", + "get hours from the date with timezone, 0-23", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + DURATION_TO_HOURS( + CelOverloadDecl.newMemberOverload( + "duration_to_hours", + "get hours from duration", + SimpleType.INT, + SimpleType.DURATION)), + TIMESTAMP_TO_MINUTES( + CelOverloadDecl.newMemberOverload( + "timestamp_to_minutes", + "get minutes from the date in UTC, 0-59", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_MINUTES_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_minutes_with_tz", + "get minutes from the date with timezone, 0-59", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + DURATION_TO_MINUTES( + CelOverloadDecl.newMemberOverload( + "duration_to_minutes", + "get minutes from duration", + SimpleType.INT, + SimpleType.DURATION)), + TIMESTAMP_TO_SECONDS( + CelOverloadDecl.newMemberOverload( + "timestamp_to_seconds", + "get seconds from the date in UTC, 0-59", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_SECONDS_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_seconds_with_tz", + "get seconds from the date with timezone, 0-59", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + DURATION_TO_SECONDS( + CelOverloadDecl.newMemberOverload( + "duration_to_seconds", + "get seconds from duration", + SimpleType.INT, + SimpleType.DURATION)), + TIMESTAMP_TO_MILLISECONDS( + CelOverloadDecl.newMemberOverload( + "timestamp_to_milliseconds", + "get milliseconds from the date in UTC, 0-999", + SimpleType.INT, + SimpleType.TIMESTAMP)), + + TIMESTAMP_TO_MILLISECONDS_WITH_TZ( + CelOverloadDecl.newMemberOverload( + "timestamp_to_milliseconds_with_tz", + "get milliseconds from the date with timezone, 0-999", + SimpleType.INT, + SimpleType.TIMESTAMP, + SimpleType.STRING)), + + DURATION_TO_MILLISECONDS( + CelOverloadDecl.newMemberOverload( + "duration_to_milliseconds", + "milliseconds from duration, 0-999", + SimpleType.INT, + SimpleType.DURATION)), + ; + private final CelOverloadDecl celOverloadDecl; + + DateTime(CelOverloadDecl overloadDecl) { + this.celOverloadDecl = overloadDecl; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + /** Overloads for performing numeric comparisons. */ + public enum Comparison implements StandardOverload { + // Less + LESS_BOOL( + CelOverloadDecl.newGlobalOverload( + "less_bool", "ordering", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL), + false), + LESS_INT64( + CelOverloadDecl.newGlobalOverload( + "less_int64", "ordering", SimpleType.BOOL, SimpleType.INT, SimpleType.INT), + false), + LESS_UINT64( + CelOverloadDecl.newGlobalOverload( + "less_uint64", "ordering", SimpleType.BOOL, SimpleType.UINT, SimpleType.UINT), + false), + LESS_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "less_double", "ordering", SimpleType.BOOL, SimpleType.DOUBLE, SimpleType.DOUBLE), + false), + LESS_STRING( + CelOverloadDecl.newGlobalOverload( + "less_string", "ordering", SimpleType.BOOL, SimpleType.STRING, SimpleType.STRING), + false), + LESS_BYTES( + CelOverloadDecl.newGlobalOverload( + "less_bytes", "ordering", SimpleType.BOOL, SimpleType.BYTES, SimpleType.BYTES), + false), + LESS_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "less_timestamp", + "ordering", + SimpleType.BOOL, + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP), + false), + LESS_DURATION( + CelOverloadDecl.newGlobalOverload( + "less_duration", + "ordering", + SimpleType.BOOL, + SimpleType.DURATION, + SimpleType.DURATION), + false), + LESS_INT64_UINT64( + CelOverloadDecl.newGlobalOverload( + "less_int64_uint64", + "Compare a signed integer value to an unsigned integer value", + SimpleType.BOOL, + SimpleType.INT, + SimpleType.UINT), + true), + LESS_UINT64_INT64( + CelOverloadDecl.newGlobalOverload( + "less_uint64_int64", + "Compare an unsigned integer value to a signed integer value", + SimpleType.BOOL, + SimpleType.UINT, + SimpleType.INT), + true), + LESS_INT64_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "less_int64_double", + "Compare a signed integer value to a double value, coalesces the integer to a" + + " double", + SimpleType.BOOL, + SimpleType.INT, + SimpleType.DOUBLE), + true), + LESS_DOUBLE_INT64( + CelOverloadDecl.newGlobalOverload( + "less_double_int64", + "Compare a double value to a signed integer value, coalesces the integer to a" + + " double", + SimpleType.BOOL, + SimpleType.DOUBLE, + SimpleType.INT), + true), + LESS_UINT64_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "less_uint64_double", + "Compare an unsigned integer value to a double value, coalesces the unsigned" + + " integer to a double", + SimpleType.BOOL, + SimpleType.UINT, + SimpleType.DOUBLE), + true), + LESS_DOUBLE_UINT64( + CelOverloadDecl.newGlobalOverload( + "less_double_uint64", + "Compare a double value to an unsigned integer value, coalesces the unsigned" + + " integer to a double", + SimpleType.BOOL, + SimpleType.DOUBLE, + SimpleType.UINT), + true), + // Less Equals + LESS_EQUALS_BOOL( + Comparison.LESS_BOOL.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_BOOL + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_INT64( + Comparison.LESS_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_UINT64( + Comparison.LESS_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_DOUBLE( + Comparison.LESS_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_STRING( + Comparison.LESS_STRING.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_STRING + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_BYTES( + Comparison.LESS_BYTES.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_BYTES + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_TIMESTAMP( + Comparison.LESS_TIMESTAMP.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_TIMESTAMP + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_DURATION( + Comparison.LESS_DURATION.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DURATION + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + false), + LESS_EQUALS_INT64_UINT64( + Comparison.LESS_INT64_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + LESS_EQUALS_UINT64_INT64( + Comparison.LESS_UINT64_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + LESS_EQUALS_INT64_DOUBLE( + Comparison.LESS_INT64_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + LESS_EQUALS_DOUBLE_INT64( + Comparison.LESS_DOUBLE_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + LESS_EQUALS_UINT64_DOUBLE( + Comparison.LESS_UINT64_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + LESS_EQUALS_DOUBLE_UINT64( + Comparison.LESS_DOUBLE_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "less_equals")) + .build(), + true), + + // Greater + GREATER_BOOL( + CelOverloadDecl.newGlobalOverload( + "greater_bool", "ordering", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL), + false), + GREATER_INT64( + CelOverloadDecl.newGlobalOverload( + "greater_int64", "ordering", SimpleType.BOOL, SimpleType.INT, SimpleType.INT), + false), + GREATER_UINT64( + CelOverloadDecl.newGlobalOverload( + "greater_uint64", "ordering", SimpleType.BOOL, SimpleType.UINT, SimpleType.UINT), + false), + GREATER_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "greater_double", + "ordering", + SimpleType.BOOL, + SimpleType.DOUBLE, + SimpleType.DOUBLE), + false), + GREATER_STRING( + CelOverloadDecl.newGlobalOverload( + "greater_string", + "ordering", + SimpleType.BOOL, + SimpleType.STRING, + SimpleType.STRING), + false), + GREATER_BYTES( + CelOverloadDecl.newGlobalOverload( + "greater_bytes", "ordering", SimpleType.BOOL, SimpleType.BYTES, SimpleType.BYTES), + false), + GREATER_TIMESTAMP( + CelOverloadDecl.newGlobalOverload( + "greater_timestamp", + "ordering", + SimpleType.BOOL, + SimpleType.TIMESTAMP, + SimpleType.TIMESTAMP), + false), + GREATER_DURATION( + CelOverloadDecl.newGlobalOverload( + "greater_duration", + "ordering", + SimpleType.BOOL, + SimpleType.DURATION, + SimpleType.DURATION), + false), + GREATER_INT64_UINT64( + CelOverloadDecl.newGlobalOverload( + "greater_int64_uint64", + "Compare a signed integer value to an unsigned integer value", + SimpleType.BOOL, + SimpleType.INT, + SimpleType.UINT), + true), + GREATER_UINT64_INT64( + CelOverloadDecl.newGlobalOverload( + "greater_uint64_int64", + "Compare an unsigned integer value to a signed integer value", + SimpleType.BOOL, + SimpleType.UINT, + SimpleType.INT), + true), + GREATER_INT64_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "greater_int64_double", + "Compare a signed integer value to a double value, coalesces the integer to a" + + " double", + SimpleType.BOOL, + SimpleType.INT, + SimpleType.DOUBLE), + true), + GREATER_DOUBLE_INT64( + CelOverloadDecl.newGlobalOverload( + "greater_double_int64", + "Compare a double value to a signed integer value, coalesces the integer to a" + + " double", + SimpleType.BOOL, + SimpleType.DOUBLE, + SimpleType.INT), + true), + GREATER_UINT64_DOUBLE( + CelOverloadDecl.newGlobalOverload( + "greater_uint64_double", + "Compare an unsigned integer value to a double value, coalesces the unsigned" + + " integer to a double", + SimpleType.BOOL, + SimpleType.UINT, + SimpleType.DOUBLE), + true), + GREATER_DOUBLE_UINT64( + CelOverloadDecl.newGlobalOverload( + "greater_double_uint64", + "Compare a double value to an unsigned integer value, coalesces the unsigned" + + " integer to a double", + SimpleType.BOOL, + SimpleType.DOUBLE, + SimpleType.UINT), + true), + + // Greater Equals + GREATER_EQUALS_BOOL( + Comparison.LESS_BOOL.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_BOOL + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_INT64( + Comparison.LESS_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_UINT64( + Comparison.LESS_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_DOUBLE( + Comparison.LESS_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_STRING( + Comparison.LESS_STRING.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_STRING + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_BYTES( + Comparison.LESS_BYTES.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_BYTES + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_TIMESTAMP( + Comparison.LESS_TIMESTAMP.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_TIMESTAMP + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_DURATION( + Comparison.LESS_DURATION.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DURATION + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + false), + GREATER_EQUALS_INT64_UINT64( + Comparison.LESS_INT64_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + GREATER_EQUALS_UINT64_INT64( + Comparison.LESS_UINT64_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + GREATER_EQUALS_INT64_DOUBLE( + Comparison.LESS_INT64_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_INT64_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + GREATER_EQUALS_DOUBLE_INT64( + Comparison.LESS_DOUBLE_INT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE_INT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + GREATER_EQUALS_UINT64_DOUBLE( + Comparison.LESS_UINT64_DOUBLE.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_UINT64_DOUBLE + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + GREATER_EQUALS_DOUBLE_UINT64( + Comparison.LESS_DOUBLE_UINT64.celOverloadDecl.toBuilder() + .setOverloadId( + Comparison.LESS_DOUBLE_UINT64 + .celOverloadDecl + .overloadId() + .replace("less", "greater_equals")) + .build(), + true), + ; + + private final CelOverloadDecl celOverloadDecl; + private final boolean isHeterogeneousComparison; + + Comparison(CelOverloadDecl overloadDecl, boolean isHeterogeneousComparison) { + this.celOverloadDecl = overloadDecl; + this.isHeterogeneousComparison = isHeterogeneousComparison; + } + + public boolean isHeterogeneousComparison() { + return isHeterogeneousComparison; + } + + @Override + public CelOverloadDecl celOverloadDecl() { + return this.celOverloadDecl; + } + } + + private Overload() {} + } + + /** Gets the declaration for this standard function. */ + private CelFunctionDecl withOverloads(Iterable overloads) { + return newCelFunctionDecl(functionName, ImmutableSet.copyOf(overloads)); + } + + CelFunctionDecl functionDecl() { + return celFunctionDecl; + } + + String functionName() { + return functionName; + } + + StandardFunction(Operator operator, StandardOverload... overloads) { + this(operator.getFunction(), overloads); + } + + StandardFunction(String functionName, StandardOverload... overloads) { + this.functionName = functionName; + this.standardOverloads = ImmutableSet.copyOf(overloads); + this.celFunctionDecl = newCelFunctionDecl(functionName, this.standardOverloads); + } + + private static CelFunctionDecl newCelFunctionDecl( + String functionName, ImmutableSet overloads) { + return CelFunctionDecl.newFunctionDeclaration( + functionName, + overloads.stream().map(StandardOverload::celOverloadDecl).collect(toImmutableSet())); + } + } + + /** Standard CEL identifiers. */ + public enum StandardIdentifier { + INT(newStandardIdentDecl(SimpleType.INT)), + UINT(newStandardIdentDecl(SimpleType.UINT)), + BOOL(newStandardIdentDecl(SimpleType.BOOL)), + DOUBLE(newStandardIdentDecl(SimpleType.DOUBLE)), + BYTES(newStandardIdentDecl(SimpleType.BYTES)), + STRING(newStandardIdentDecl(SimpleType.STRING)), + DYN(newStandardIdentDecl(SimpleType.DYN)), + TYPE(newStandardIdentDecl("type", SimpleType.DYN)), + NULL_TYPE(newStandardIdentDecl("null_type", SimpleType.NULL_TYPE)), + LIST(newStandardIdentDecl("list", ListType.create(SimpleType.DYN))), + MAP(newStandardIdentDecl("map", MapType.create(SimpleType.DYN, SimpleType.DYN))), + ; + + private static CelIdentDecl newStandardIdentDecl(CelType celType) { + return newStandardIdentDecl(CelTypes.format(celType), celType); + } + + private static CelIdentDecl newStandardIdentDecl(String identName, CelType celType) { + return CelIdentDecl.newBuilder() + .setName(identName) + .setType(TypeType.create(celType)) + .setDoc("type denotation") + .build(); + } + + private final CelIdentDecl identDecl; + + CelIdentDecl identDecl() { + return identDecl; + } + + StandardIdentifier(CelIdentDecl identDecl) { + this.identDecl = identDecl; + } + } + + /** General interface for defining a standard function overload. */ + @Immutable + public interface StandardOverload { + CelOverloadDecl celOverloadDecl(); + } + + /** Set of all standard function names. */ + public static ImmutableSet getAllFunctionNames() { + return stream(StandardFunction.values()).map(f -> f.functionName).collect(toImmutableSet()); + } + + /** + * Deprecated standard functions maintained for backward compatibility reasons. + * + *

Note: Keep this package-private. + */ + static ImmutableSet deprecatedFunctions() { + return DEPRECATED_STANDARD_FUNCTIONS; + } + + /** Builder for constructing the set of standard function/identifiers. */ + public static final class Builder { + + private ImmutableSet includeFunctions; + private ImmutableSet excludeFunctions; + private FunctionFilter functionFilter; + + private ImmutableSet includeIdentifiers; + private ImmutableSet excludeIdentifiers; + private IdentifierFilter identifierFilter; + + @CanIgnoreReturnValue + public Builder excludeFunctions(StandardFunction... functions) { + return excludeFunctions(ImmutableSet.copyOf(functions)); + } + + @CanIgnoreReturnValue + public Builder excludeFunctions(Iterable functions) { + this.excludeFunctions = checkNotNull(ImmutableSet.copyOf(functions)); + return this; + } + + @CanIgnoreReturnValue + public Builder includeFunctions(StandardFunction... functions) { + return includeFunctions(ImmutableSet.copyOf(functions)); + } + + @CanIgnoreReturnValue + public Builder includeFunctions(Iterable functions) { + this.includeFunctions = checkNotNull(ImmutableSet.copyOf(functions)); + return this; + } + + @CanIgnoreReturnValue + public Builder filterFunctions(FunctionFilter functionFilter) { + this.functionFilter = functionFilter; + return this; + } + + @CanIgnoreReturnValue + public Builder excludeIdentifiers(StandardIdentifier... identifiers) { + return excludeIdentifiers(ImmutableSet.copyOf(identifiers)); + } + + @CanIgnoreReturnValue + public Builder excludeIdentifiers(Iterable identifiers) { + this.excludeIdentifiers = checkNotNull(ImmutableSet.copyOf(identifiers)); + return this; + } + + @CanIgnoreReturnValue + public Builder includeIdentifiers(StandardIdentifier... identifiers) { + return includeIdentifiers(ImmutableSet.copyOf(identifiers)); + } + + @CanIgnoreReturnValue + public Builder includeIdentifiers(Iterable identifiers) { + this.includeIdentifiers = checkNotNull(ImmutableSet.copyOf(identifiers)); + return this; + } + + @CanIgnoreReturnValue + public Builder filterIdentifiers(IdentifierFilter identifierFilter) { + this.identifierFilter = identifierFilter; + return this; + } + + private static void assertOneSettingIsSet( + boolean a, boolean b, boolean c, String errorMessage) { + int count = 0; + if (a) { + count++; + } + if (b) { + count++; + } + if (c) { + count++; + } + + if (count > 1) { + throw new IllegalArgumentException(errorMessage); + } + } + + CelStandardDeclarations build() { + boolean hasIncludeFunctions = !this.includeFunctions.isEmpty(); + boolean hasExcludeFunctions = !this.excludeFunctions.isEmpty(); + boolean hasFilterFunction = this.functionFilter != null; + assertOneSettingIsSet( + hasIncludeFunctions, + hasExcludeFunctions, + hasFilterFunction, + "You may only populate one of the following builder methods: includeFunctions," + + " excludeFunctions or filterFunctions"); + boolean hasIncludeIdentifiers = !this.includeIdentifiers.isEmpty(); + boolean hasExcludeIdentifiers = !this.excludeIdentifiers.isEmpty(); + boolean hasIdentifierFilter = this.identifierFilter != null; + assertOneSettingIsSet( + hasIncludeIdentifiers, + hasExcludeIdentifiers, + hasIdentifierFilter, + "You may only populate one of the following builder methods: includeIdentifiers," + + " excludeIdentifiers or filterIdentifiers"); + + ImmutableSet.Builder functionDeclBuilder = ImmutableSet.builder(); + for (StandardFunction standardFunction : StandardFunction.values()) { + if (hasIncludeFunctions) { + if (this.includeFunctions.contains(standardFunction)) { + functionDeclBuilder.add(standardFunction.celFunctionDecl); + } + continue; + } + if (hasExcludeFunctions) { + if (!this.excludeFunctions.contains(standardFunction)) { + functionDeclBuilder.add(standardFunction.celFunctionDecl); + } + continue; + } + if (hasFilterFunction) { + ImmutableSet.Builder overloadBuilder = ImmutableSet.builder(); + for (StandardOverload standardOverload : standardFunction.standardOverloads) { + boolean includeOverload = functionFilter.include(standardFunction, standardOverload); + if (includeOverload) { + overloadBuilder.add(standardOverload); + } + } + + ImmutableSet overloads = overloadBuilder.build(); + if (!overloads.isEmpty()) { + functionDeclBuilder.add(standardFunction.withOverloads(overloadBuilder.build())); + } + continue; + } + + functionDeclBuilder.add(standardFunction.celFunctionDecl); + } + + ImmutableSet.Builder identBuilder = ImmutableSet.builder(); + for (StandardIdentifier standardIdentifier : StandardIdentifier.values()) { + if (hasIncludeIdentifiers) { + if (this.includeIdentifiers.contains(standardIdentifier)) { + identBuilder.add(standardIdentifier.identDecl); + } + continue; + } + + if (hasExcludeIdentifiers) { + if (!this.excludeIdentifiers.contains(standardIdentifier)) { + identBuilder.add(standardIdentifier.identDecl); + } + continue; + } + + if (hasIdentifierFilter) { + boolean includeIdent = identifierFilter.include(standardIdentifier); + if (includeIdent) { + identBuilder.add(standardIdentifier.identDecl); + } + continue; + } + + identBuilder.add(standardIdentifier.identDecl); + } + + return new CelStandardDeclarations(functionDeclBuilder.build(), identBuilder.build()); + } + + private Builder() { + this.includeFunctions = ImmutableSet.of(); + this.excludeFunctions = ImmutableSet.of(); + this.includeIdentifiers = ImmutableSet.of(); + this.excludeIdentifiers = ImmutableSet.of(); + } + + /** + * Functional interface for filtering standard functions. Returning true in the callback will + * include the function in the environment. + */ + @FunctionalInterface + public interface FunctionFilter { + boolean include(StandardFunction standardFunction, StandardOverload standardOverload); + } + + /** + * Functional interface for filtering standard identifiers. Returning true in the callback will + * include the identifier in the environment. + */ + @FunctionalInterface + public interface IdentifierFilter { + boolean include(StandardIdentifier standardIdentifier); + } + } + + public static Builder newBuilder() { + return new Builder(); + } + + ImmutableSet functionDecls() { + return celFunctionDecls; + } + + ImmutableSet identifierDecls() { + return celIdentDecls; + } + + private CelStandardDeclarations( + ImmutableSet celFunctionDecls, ImmutableSet celIdentDecls) { + this.celFunctionDecls = celFunctionDecls; + this.celIdentDecls = celIdentDecls; + } +} diff --git a/checker/src/main/java/dev/cel/checker/Env.java b/checker/src/main/java/dev/cel/checker/Env.java index 613bef166..588b98c3e 100644 --- a/checker/src/main/java/dev/cel/checker/Env.java +++ b/checker/src/main/java/dev/cel/checker/Env.java @@ -27,6 +27,8 @@ import com.google.common.collect.Lists; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.checker.CelStandardDeclarations.StandardFunction.Overload.Comparison; +import dev.cel.checker.CelStandardDeclarations.StandardFunction.Overload.Conversions; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; @@ -38,6 +40,7 @@ import dev.cel.common.ast.CelReference; import dev.cel.common.internal.Errors; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypes; import dev.cel.common.types.SimpleType; @@ -219,9 +222,53 @@ public static Env standard(Errors errors, CelOptions celOptions) { * subsequent declarations with the same signature. */ public static Env standard(Errors errors, TypeProvider typeProvider, CelOptions celOptions) { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .filterFunctions( + (function, overload) -> { + switch (function) { + case INT: + if (!celOptions.enableUnsignedLongs() + && overload.equals(Conversions.INT64_TO_INT64)) { + return false; + } + break; + case TIMESTAMP: + // TODO: Remove this flag guard once the feature has been + // auto-enabled. + if (!celOptions.enableTimestampEpoch() + && overload.equals(Conversions.INT64_TO_TIMESTAMP)) { + return false; + } + break; + default: + if (!celOptions.enableHeterogeneousNumericComparisons() + && overload instanceof Comparison) { + Comparison comparison = (Comparison) overload; + if (comparison.isHeterogeneousComparison()) { + return false; + } + } + break; + } + return true; + }) + .build(); + + return standard(celStandardDeclaration, errors, typeProvider, celOptions); + } + + public static Env standard( + CelStandardDeclarations celStandardDeclaration, + Errors errors, + TypeProvider typeProvider, + CelOptions celOptions) { Env env = Env.unconfigured(errors, typeProvider, celOptions); // Isolate the standard declarations into their own scope for forward compatibility. - Standard.add(env); + CelStandardDeclarations.deprecatedFunctions().forEach(env::add); + celStandardDeclaration.functionDecls().forEach(env::add); + celStandardDeclaration.identifierDecls().forEach(env::add); + env.enterScope(); return env; } @@ -296,7 +343,7 @@ public Map getTypeMap() { @Deprecated public Type getType(Expr expr) { Preconditions.checkNotNull(expr); - return CelTypes.celTypeToType(getType(CelExprConverter.fromExpr(expr))); + return CelProtoTypes.celTypeToType(getType(CelExprConverter.fromExpr(expr))); } /** @@ -349,7 +396,7 @@ public Env add(Decl decl) { CelIdentDecl.Builder identBuilder = CelIdentDecl.newBuilder() .setName(decl.getName()) - .setType(CelTypes.typeToCelType(decl.getIdent().getType())) + .setType(CelProtoTypes.typeToCelType(decl.getIdent().getType())) // Note: Setting doc and constant value exists for compatibility reason. This should // not be set by the users. .setDoc(decl.getIdent().getDoc()); @@ -394,7 +441,7 @@ public Env add(CelIdentDecl celIdentDecl) { @CanIgnoreReturnValue @Deprecated public Env add(String name, Type type) { - return add(CelIdentDecl.newIdentDeclaration(name, CelTypes.typeToCelType(type))); + return add(CelIdentDecl.newIdentDeclaration(name, CelProtoTypes.typeToCelType(type))); } /** @@ -720,7 +767,7 @@ public IdentBuilder(String name) { @CanIgnoreReturnValue public IdentBuilder type(Type value) { Preconditions.checkNotNull(value); - builder.setType(CelTypes.typeToCelType(Preconditions.checkNotNull(value))); + builder.setType(CelProtoTypes.typeToCelType(Preconditions.checkNotNull(value))); return this; } @@ -802,12 +849,12 @@ public FunctionBuilder add(String id, Type resultType, Type... argTypes) { public FunctionBuilder add(String id, Type resultType, Iterable argTypes) { ImmutableList.Builder argumentBuilder = new ImmutableList.Builder<>(); for (Type type : argTypes) { - argumentBuilder.add(CelTypes.typeToCelType(type)); + argumentBuilder.add(CelProtoTypes.typeToCelType(type)); } this.overloads.add( CelOverloadDecl.newBuilder() .setOverloadId(id) - .setResultType(CelTypes.typeToCelType(resultType)) + .setResultType(CelProtoTypes.typeToCelType(resultType)) .addParameterTypes(argumentBuilder.build()) .setIsInstanceFunction(isInstance) .build()); @@ -827,12 +874,12 @@ public FunctionBuilder add( String id, List typeParams, Type resultType, Iterable argTypes) { ImmutableList.Builder argumentBuilder = new ImmutableList.Builder<>(); for (Type type : argTypes) { - argumentBuilder.add(CelTypes.typeToCelType(type)); + argumentBuilder.add(CelProtoTypes.typeToCelType(type)); } this.overloads.add( CelOverloadDecl.newBuilder() .setOverloadId(id) - .setResultType(CelTypes.typeToCelType(resultType)) + .setResultType(CelProtoTypes.typeToCelType(resultType)) .addParameterTypes(argumentBuilder.build()) .setIsInstanceFunction(isInstance) .build()); diff --git a/checker/src/main/java/dev/cel/checker/ExprChecker.java b/checker/src/main/java/dev/cel/checker/ExprChecker.java index f4f485e08..c39e4d00c 100644 --- a/checker/src/main/java/dev/cel/checker/ExprChecker.java +++ b/checker/src/main/java/dev/cel/checker/ExprChecker.java @@ -35,6 +35,7 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelReference; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypes; import dev.cel.common.types.ListType; @@ -88,7 +89,7 @@ public static CheckedExpr typecheck( Env env, String inContainer, ParsedExpr parsedExpr, Optional expectedResultType) { Optional type = expectedResultType.isPresent() - ? Optional.of(CelTypes.typeToCelType(expectedResultType.get())) + ? Optional.of(CelProtoTypes.typeToCelType(expectedResultType.get())) : Optional.absent(); CelAbstractSyntaxTree ast = typecheck( diff --git a/checker/src/main/java/dev/cel/checker/Standard.java b/checker/src/main/java/dev/cel/checker/Standard.java deleted file mode 100644 index acdc185eb..000000000 --- a/checker/src/main/java/dev/cel/checker/Standard.java +++ /dev/null @@ -1,846 +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.checker; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import dev.cel.common.CelFunctionDecl; -import dev.cel.common.CelOverloadDecl; -import dev.cel.common.annotations.Internal; -import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; -import dev.cel.common.types.ListType; -import dev.cel.common.types.MapType; -import dev.cel.common.types.SimpleType; -import dev.cel.common.types.TypeParamType; -import dev.cel.common.types.TypeType; -import dev.cel.parser.Operator; - -/** - * Standard declarations for CEL. - * - *

CEL Library Internals. Do Not Use. - */ -@Internal -public final class Standard { - - private static final ImmutableList CORE_FUNCTION_DECLARATIONS = - coreFunctionDeclarations(); - 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. - * - *

Note: Standard declarations should be provided in their own scope to avoid collisions with - * custom declarations. The {@link Env#standard} helper method does this by default. - */ - @CanIgnoreReturnValue - public static Env add(Env env) { - CORE_FUNCTION_DECLARATIONS.forEach(env::add); - CORE_IDENT_DECLARATIONS.forEach(env::add); - - // TODO: Remove this flag guard once the feature has been auto-enabled. - 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; - } - - /** Do the expensive work of setting up all the objects in the environment. */ - private static ImmutableList coreIdentDeclarations() { - ImmutableList.Builder identDeclBuilder = ImmutableList.builder(); - - // Type Denotations - for (CelType type : - ImmutableList.of( - SimpleType.INT, - SimpleType.UINT, - SimpleType.BOOL, - SimpleType.DOUBLE, - SimpleType.BYTES, - SimpleType.STRING, - SimpleType.DYN)) { - identDeclBuilder.add( - CelIdentDecl.newBuilder() - .setName(CelTypes.format(type)) - .setType(TypeType.create(type)) - .setDoc("type denotation") - .build()); - } - identDeclBuilder.add( - CelIdentDecl.newBuilder() - .setName("type") - .setType(TypeType.create(SimpleType.DYN)) - .setDoc("type denotation") - .build()); - identDeclBuilder.add( - CelIdentDecl.newBuilder() - .setName("null_type") - .setType(TypeType.create(SimpleType.NULL_TYPE)) - .setDoc("type denotation") - .build()); - identDeclBuilder.add( - CelIdentDecl.newBuilder() - .setName("list") - .setType(TypeType.create(ListType.create(SimpleType.DYN))) - .setDoc("type denotation") - .build()); - identDeclBuilder.add( - CelIdentDecl.newBuilder() - .setName("map") - .setType(TypeType.create(MapType.create(SimpleType.DYN, SimpleType.DYN))) - .setDoc("type denotation") - .build()); - - return identDeclBuilder.build(); - } - - /** Do the expensive work of setting up all the objects in the environment. */ - private static ImmutableList coreFunctionDeclarations() { - // Some shortcuts we use when building declarations. - TypeParamType typeParamA = TypeParamType.create("A"); - ListType listOfA = ListType.create(typeParamA); - TypeParamType typeParamB = TypeParamType.create("B"); - MapType mapOfAb = MapType.create(typeParamA, typeParamB); - - ImmutableList.Builder celFunctionDeclBuilder = ImmutableList.builder(); - - // Booleans - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.CONDITIONAL.getFunction(), - CelOverloadDecl.newGlobalOverload( - "conditional", - "conditional", - typeParamA, - SimpleType.BOOL, - typeParamA, - typeParamA))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.LOGICAL_AND.getFunction(), - CelOverloadDecl.newGlobalOverload( - "logical_and", "logical_and", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.LOGICAL_OR.getFunction(), - CelOverloadDecl.newGlobalOverload( - "logical_or", "logical or", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.LOGICAL_NOT.getFunction(), - CelOverloadDecl.newGlobalOverload( - "logical_not", "logical not", SimpleType.BOOL, SimpleType.BOOL))); - CelFunctionDecl notStrictlyFalse = - CelFunctionDecl.newFunctionDeclaration( - Operator.OLD_NOT_STRICTLY_FALSE.getFunction(), - CelOverloadDecl.newGlobalOverload( - "not_strictly_false", - "false if argument is false, true otherwise (including errors and unknowns)", - SimpleType.BOOL, - SimpleType.BOOL)); - celFunctionDeclBuilder.add(notStrictlyFalse); - celFunctionDeclBuilder.add( - CelFunctionDecl.newBuilder() - .setName(Operator.NOT_STRICTLY_FALSE.getFunction()) - .addOverloads(sameAs(notStrictlyFalse, "", "")) - .build()); - - // Relations - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.EQUALS.getFunction(), - CelOverloadDecl.newGlobalOverload( - "equals", "equality", SimpleType.BOOL, typeParamA, typeParamA))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.NOT_EQUALS.getFunction(), - CelOverloadDecl.newGlobalOverload( - "not_equals", "inequality", SimpleType.BOOL, typeParamA, typeParamA))); - - // Algebra - CelFunctionDecl commonArithmetic = - CelFunctionDecl.newFunctionDeclaration( - Operator.SUBTRACT.getFunction(), - CelOverloadDecl.newGlobalOverload( - "common_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "common_uint64", "arithmetic", SimpleType.UINT, SimpleType.UINT, SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "common_double", - "arithmetic", - SimpleType.DOUBLE, - SimpleType.DOUBLE, - SimpleType.DOUBLE)); - CelFunctionDecl subtract = - CelFunctionDecl.newBuilder() - .setName(Operator.SUBTRACT.getFunction()) - .addOverloads(sameAs(commonArithmetic, "common", "subtract")) - .addOverloads( - CelOverloadDecl.newGlobalOverload( - "subtract_timestamp_timestamp", - "arithmetic", - SimpleType.DURATION, - SimpleType.TIMESTAMP, - SimpleType.TIMESTAMP), - CelOverloadDecl.newGlobalOverload( - "subtract_timestamp_duration", - "arithmetic", - SimpleType.TIMESTAMP, - SimpleType.TIMESTAMP, - SimpleType.DURATION), - CelOverloadDecl.newGlobalOverload( - "subtract_duration_duration", - "arithmetic", - SimpleType.DURATION, - SimpleType.DURATION, - SimpleType.DURATION)) - .build(); - celFunctionDeclBuilder.add(subtract); - celFunctionDeclBuilder.add( - CelFunctionDecl.newBuilder() - .setName(Operator.MULTIPLY.getFunction()) - .addOverloads(sameAs(commonArithmetic, "common", "multiply")) - .build()); - celFunctionDeclBuilder.add( - CelFunctionDecl.newBuilder() - .setName(Operator.DIVIDE.getFunction()) - .addOverloads(sameAs(commonArithmetic, "common", "divide")) - .build()); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.MODULO.getFunction(), - CelOverloadDecl.newGlobalOverload( - "modulo_int64", "arithmetic", SimpleType.INT, SimpleType.INT, SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "modulo_uint64", "arithmetic", SimpleType.UINT, SimpleType.UINT, SimpleType.UINT))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newBuilder() - .setName(Operator.ADD.getFunction()) - .addOverloads(sameAs(commonArithmetic, "common", "add")) - .addOverloads( - CelOverloadDecl.newGlobalOverload( - "add_string", - "string concatenation", - SimpleType.STRING, - SimpleType.STRING, - SimpleType.STRING), - CelOverloadDecl.newGlobalOverload( - "add_bytes", - "bytes concatenation", - SimpleType.BYTES, - SimpleType.BYTES, - SimpleType.BYTES), - CelOverloadDecl.newGlobalOverload( - "add_list", "list concatenation", listOfA, listOfA, listOfA), - CelOverloadDecl.newGlobalOverload( - "add_timestamp_duration", - "arithmetic", - SimpleType.TIMESTAMP, - SimpleType.TIMESTAMP, - SimpleType.DURATION), - CelOverloadDecl.newGlobalOverload( - "add_duration_timestamp", - "arithmetic", - SimpleType.TIMESTAMP, - SimpleType.DURATION, - SimpleType.TIMESTAMP), - CelOverloadDecl.newGlobalOverload( - "add_duration_duration", - "arithmetic", - SimpleType.DURATION, - SimpleType.DURATION, - SimpleType.DURATION)) - .build()); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.NEGATE.getFunction(), - CelOverloadDecl.newGlobalOverload( - "negate_int64", "negation", SimpleType.INT, SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "negate_double", "negation", SimpleType.DOUBLE, SimpleType.DOUBLE))); - - // Index - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Operator.INDEX.getFunction(), - CelOverloadDecl.newGlobalOverload( - "index_list", "list indexing", typeParamA, listOfA, SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "index_map", "map indexing", typeParamB, mapOfAb, typeParamA))); - - // Collections - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - "size", - CelOverloadDecl.newGlobalOverload( - "size_string", "string length", SimpleType.INT, SimpleType.STRING), - CelOverloadDecl.newGlobalOverload( - "size_bytes", "bytes length", SimpleType.INT, SimpleType.BYTES), - CelOverloadDecl.newGlobalOverload("size_list", "list size", SimpleType.INT, listOfA), - CelOverloadDecl.newGlobalOverload("size_map", "map size", SimpleType.INT, mapOfAb), - CelOverloadDecl.newMemberOverload( - "string_size", "string length", SimpleType.INT, SimpleType.STRING), - CelOverloadDecl.newMemberOverload( - "bytes_size", "bytes length", SimpleType.INT, SimpleType.BYTES), - CelOverloadDecl.newMemberOverload("list_size", "list size", SimpleType.INT, listOfA), - CelOverloadDecl.newMemberOverload("map_size", "map size", SimpleType.INT, mapOfAb))); - - // Set membership 'in' operator. - CelFunctionDecl inOperator = - CelFunctionDecl.newFunctionDeclaration( - Operator.OLD_IN.getFunction(), - CelOverloadDecl.newGlobalOverload( - "in_list", "list membership", SimpleType.BOOL, typeParamA, listOfA), - CelOverloadDecl.newGlobalOverload( - "in_map", "map key membership", SimpleType.BOOL, typeParamA, mapOfAb)); - celFunctionDeclBuilder.add(inOperator); - celFunctionDeclBuilder.add( - CelFunctionDecl.newBuilder() - .setName(Operator.IN.getFunction()) - .addOverloads(sameAs(inOperator, "", "")) - .build()); - - // Conversions to type - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.TYPE.getFunction(), - CelOverloadDecl.newGlobalOverload( - "type", "returns type of value", TypeType.create(typeParamA), typeParamA))); - - // Conversions to int - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.INT.getFunction(), - CelOverloadDecl.newGlobalOverload( - "uint64_to_int64", "type conversion", SimpleType.INT, SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "double_to_int64", "type conversion", SimpleType.INT, SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "string_to_int64", "type conversion", SimpleType.INT, SimpleType.STRING), - CelOverloadDecl.newGlobalOverload( - "timestamp_to_int64", - "Convert timestamp to int64 in seconds since Unix epoch.", - SimpleType.INT, - SimpleType.TIMESTAMP))); - - // Conversions to uint - 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( - "double_to_uint64", "type conversion", SimpleType.UINT, SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "string_to_uint64", "type conversion", SimpleType.UINT, SimpleType.STRING))); - - // Conversions to double - 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( - "uint64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "string_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.STRING))); - - // Conversions to string - 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( - "uint64_to_string", "type conversion", SimpleType.STRING, SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "double_to_string", "type conversion", SimpleType.STRING, SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "bytes_to_string", "type conversion", SimpleType.STRING, SimpleType.BYTES), - CelOverloadDecl.newGlobalOverload( - "timestamp_to_string", "type_conversion", SimpleType.STRING, SimpleType.TIMESTAMP), - CelOverloadDecl.newGlobalOverload( - "duration_to_string", "type_conversion", SimpleType.STRING, SimpleType.DURATION))); - - // Conversions to bytes - 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))); - - // Conversions to dyn - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.DYN.getFunction(), - CelOverloadDecl.newGlobalOverload( - "to_dyn", "type conversion", SimpleType.DYN, typeParamA))); - - // Conversions to Duration - 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), - CelOverloadDecl.newGlobalOverload( - "string_to_bool", "type conversion", SimpleType.BOOL, SimpleType.STRING))); - - // String functions - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.MATCHES.getFunction(), - CelOverloadDecl.newGlobalOverload( - "matches", - "matches first argument against regular expression in second argument", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.MATCHES.getFunction(), - CelOverloadDecl.newMemberOverload( - "matches_string", - "matches the self argument against regular expression in first argument", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.CONTAINS.getFunction(), - CelOverloadDecl.newMemberOverload( - "contains_string", - "tests whether the string operand contains the substring", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.ENDS_WITH.getFunction(), - CelOverloadDecl.newMemberOverload( - "ends_with_string", - "tests whether the string operand ends with the suffix argument", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.STARTS_WITH.getFunction(), - CelOverloadDecl.newMemberOverload( - "starts_with_string", - "tests whether the string operand starts with the prefix argument", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING))); - - // Date/time functions - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_FULL_YEAR.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_year", - "get year from the date in UTC", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_year_with_tz", - "get year from the date with timezone", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_MONTH.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_month", - "get month from the date in UTC, 0-11", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_month_with_tz", - "get month from the date with timezone, 0-11", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - 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", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_day_of_year_with_tz", - "get day of year from the date with timezone, zero-based indexing", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - 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", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_day_of_month_with_tz", - "get day of month from the date with timezone, zero-based indexing", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - 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", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_day_of_month_1_based_with_tz", - "get day of month from the date with timezone, one-based indexing", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - 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", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_day_of_week_with_tz", - "get day of week from the date with timezone, zero-based, zero for Sunday", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_HOURS.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_hours", - "get hours from the date in UTC, 0-23", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_hours_with_tz", - "get hours from the date with timezone, 0-23", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING), - CelOverloadDecl.newMemberOverload( - "duration_to_hours", - "get hours from duration", - SimpleType.INT, - SimpleType.DURATION))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_MINUTES.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_minutes", - "get minutes from the date in UTC, 0-59", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_minutes_with_tz", - "get minutes from the date with timezone, 0-59", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING), - CelOverloadDecl.newMemberOverload( - "duration_to_minutes", - "get minutes from duration", - SimpleType.INT, - SimpleType.DURATION))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_SECONDS.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_seconds", - "get seconds from the date in UTC, 0-59", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_seconds_with_tz", - "get seconds from the date with timezone, 0-59", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING), - CelOverloadDecl.newMemberOverload( - "duration_to_seconds", - "get seconds from duration", - SimpleType.INT, - SimpleType.DURATION))); - - celFunctionDeclBuilder.add( - CelFunctionDecl.newFunctionDeclaration( - Function.GET_MILLISECONDS.getFunction(), - CelOverloadDecl.newMemberOverload( - "timestamp_to_milliseconds", - "get milliseconds from the date in UTC, 0-999", - SimpleType.INT, - SimpleType.TIMESTAMP), - CelOverloadDecl.newMemberOverload( - "timestamp_to_milliseconds_with_tz", - "get milliseconds from the date with timezone, 0-999", - SimpleType.INT, - SimpleType.TIMESTAMP, - SimpleType.STRING), - CelOverloadDecl.newMemberOverload( - "duration_to_milliseconds", - "milliseconds from duration, 0-999", - SimpleType.INT, - SimpleType.DURATION))); - - return celFunctionDeclBuilder.build(); - } - - private static ImmutableList timestampConversionDeclarations(boolean withEpoch) { - CelFunctionDecl.Builder timestampBuilder = - CelFunctionDecl.newBuilder() - .setName("timestamp") - .addOverloads( - CelOverloadDecl.newGlobalOverload( - "string_to_timestamp", - "Type conversion of strings to timestamps according to RFC3339. Example:" - + " \"1972-01-01T10:00:20.021-05:00\".", - SimpleType.TIMESTAMP, - SimpleType.STRING), - CelOverloadDecl.newGlobalOverload( - "timestamp_to_timestamp", - "type conversion (identity)", - SimpleType.TIMESTAMP, - SimpleType.TIMESTAMP)); - if (withEpoch) { - timestampBuilder.addOverloads( - CelOverloadDecl.newGlobalOverload( - "int64_to_timestamp", - "Type conversion of integers as Unix epoch seconds to timestamps.", - SimpleType.TIMESTAMP, - SimpleType.INT)); - } - return ImmutableList.of(timestampBuilder.build()); - } - - private static ImmutableList numericComparisonDeclarations( - boolean withHeterogeneousComparisons) { - CelFunctionDecl.Builder lessBuilder = - CelFunctionDecl.newBuilder() - .setName(Operator.LESS.getFunction()) - .addOverloads( - CelOverloadDecl.newGlobalOverload( - "less_bool", "ordering", SimpleType.BOOL, SimpleType.BOOL, SimpleType.BOOL), - CelOverloadDecl.newGlobalOverload( - "less_int64", "ordering", SimpleType.BOOL, SimpleType.INT, SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "less_uint64", "ordering", SimpleType.BOOL, SimpleType.UINT, SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "less_double", - "ordering", - SimpleType.BOOL, - SimpleType.DOUBLE, - SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "less_string", - "ordering", - SimpleType.BOOL, - SimpleType.STRING, - SimpleType.STRING), - CelOverloadDecl.newGlobalOverload( - "less_bytes", "ordering", SimpleType.BOOL, SimpleType.BYTES, SimpleType.BYTES), - CelOverloadDecl.newGlobalOverload( - "less_timestamp", - "ordering", - SimpleType.BOOL, - SimpleType.TIMESTAMP, - SimpleType.TIMESTAMP), - CelOverloadDecl.newGlobalOverload( - "less_duration", - "ordering", - SimpleType.BOOL, - SimpleType.DURATION, - SimpleType.DURATION)); - - if (withHeterogeneousComparisons) { - lessBuilder.addOverloads( - CelOverloadDecl.newGlobalOverload( - "less_int64_uint64", - "Compare a signed integer value to an unsigned integer value", - SimpleType.BOOL, - SimpleType.INT, - SimpleType.UINT), - CelOverloadDecl.newGlobalOverload( - "less_uint64_int64", - "Compare an unsigned integer value to a signed integer value", - SimpleType.BOOL, - SimpleType.UINT, - SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "less_int64_double", - "Compare a signed integer value to a double value, coalesces the integer to a double", - SimpleType.BOOL, - SimpleType.INT, - SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "less_double_int64", - "Compare a double value to a signed integer value, coalesces the integer to a double", - SimpleType.BOOL, - SimpleType.DOUBLE, - SimpleType.INT), - CelOverloadDecl.newGlobalOverload( - "less_uint64_double", - "Compare an unsigned integer value to a double value, coalesces the unsigned integer" - + " to a double", - SimpleType.BOOL, - SimpleType.UINT, - SimpleType.DOUBLE), - CelOverloadDecl.newGlobalOverload( - "less_double_uint64", - "Compare a double value to an unsigned integer value, coalesces the unsigned integer" - + " to a double", - SimpleType.BOOL, - SimpleType.DOUBLE, - SimpleType.UINT)); - } - - CelFunctionDecl less = lessBuilder.build(); - return ImmutableList.of( - less, - CelFunctionDecl.newBuilder() - .setName(Operator.LESS_EQUALS.getFunction()) - .addOverloads(sameAs(less, "less", "less_equals")) - .build(), - CelFunctionDecl.newBuilder() - .setName(Operator.GREATER.getFunction()) - .addOverloads(sameAs(less, "less", "greater")) - .build(), - CelFunctionDecl.newBuilder() - .setName(Operator.GREATER_EQUALS.getFunction()) - .addOverloads(sameAs(less, "less", "greater_equals")) - .build()); - } - - /** - * Add the overloads of another function to this function, after replacing the overload id as - * specified. - */ - private static ImmutableList sameAs( - CelFunctionDecl func, String idPart, String idPartReplace) { - ImmutableList.Builder overloads = new ImmutableList.Builder<>(); - Preconditions.checkNotNull(func); - for (CelOverloadDecl overload : func.overloads()) { - overloads.add( - overload.toBuilder() - .setOverloadId(overload.overloadId().replace(idPart, idPartReplace)) - .build()); - } - return overloads.build(); - } - - private Standard() {} -} diff --git a/checker/src/main/java/dev/cel/checker/TypeProvider.java b/checker/src/main/java/dev/cel/checker/TypeProvider.java index 10ce2a7d6..2dd5261ab 100644 --- a/checker/src/main/java/dev/cel/checker/TypeProvider.java +++ b/checker/src/main/java/dev/cel/checker/TypeProvider.java @@ -18,8 +18,8 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import java.util.Optional; import java.util.function.Function; import org.jspecify.annotations.Nullable; @@ -38,7 +38,7 @@ public interface TypeProvider { /** Lookup the a {@link CelType} given a qualified {@code typeName}. Returns null if not found. */ default Optional lookupCelType(String typeName) { Type type = lookupType(typeName); - return Optional.ofNullable(type).map(CelTypes::typeToCelType); + return Optional.ofNullable(type).map(CelProtoTypes::typeToCelType); } /** Lookup the {@code Integer} enum value given an {@code enumName}. Returns null if not found. */ @@ -61,7 +61,7 @@ default Optional lookupCelType(String typeName) { * check is supported via the ('has') macro. */ default @Nullable FieldType lookupFieldType(CelType type, String fieldName) { - return lookupFieldType(CelTypes.celTypeToType(type), fieldName); + return lookupFieldType(CelProtoTypes.celTypeToType(type), fieldName); } /** @@ -89,7 +89,7 @@ public abstract class FieldType { public abstract Type type(); public CelType celType() { - return CelTypes.typeToCelType(type()); + return CelProtoTypes.typeToCelType(type()); } /** Create a new {@code FieldType} instance from the provided {@code type}. */ diff --git a/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java b/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java index 4d1e0ea32..b2ac51d95 100644 --- a/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java +++ b/checker/src/main/java/dev/cel/checker/TypeProviderLegacyImpl.java @@ -18,9 +18,9 @@ import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.annotations.Internal; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.EnumType; import dev.cel.common.types.ProtoMessageType; import dev.cel.common.types.StructType; @@ -45,7 +45,7 @@ final class TypeProviderLegacyImpl implements TypeProvider { @Override public @Nullable Type lookupType(String typeName) { - return lookupCelType(typeName).map(CelTypes::celTypeToType).orElse(null); + return lookupCelType(typeName).map(CelProtoTypes::celTypeToType).orElse(null); } @Override @@ -65,13 +65,13 @@ public Optional lookupCelType(String typeName) { return structType .findField(fieldName) - .map(f -> FieldType.of(CelTypes.celTypeToType(f.type()))) + .map(f -> FieldType.of(CelProtoTypes.celTypeToType(f.type()))) .orElse(null); } @Override public @Nullable FieldType lookupFieldType(Type type, String fieldName) { - return lookupFieldType(CelTypes.typeToCelType(type), fieldName); + return lookupFieldType(CelProtoTypes.typeToCelType(type), fieldName); } @Override @@ -114,7 +114,8 @@ public Optional lookupCelType(String typeName) { .map( et -> ExtensionFieldType.of( - CelTypes.celTypeToType(et.type()), CelTypes.celTypeToType(et.messageType()))) + CelProtoTypes.celTypeToType(et.type()), + CelProtoTypes.celTypeToType(et.messageType()))) .orElse(null); } } diff --git a/checker/src/main/java/dev/cel/checker/Types.java b/checker/src/main/java/dev/cel/checker/Types.java index 7f249fc92..62a3b66e9 100644 --- a/checker/src/main/java/dev/cel/checker/Types.java +++ b/checker/src/main/java/dev/cel/checker/Types.java @@ -26,8 +26,8 @@ import com.google.protobuf.NullValue; import dev.cel.common.annotations.Internal; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.NullableType; @@ -177,7 +177,7 @@ public static Type createWrapper(Type type) { */ @Deprecated public static boolean isDynOrError(Type type) { - return isDynOrError(CelTypes.typeToCelType(type)); + return isDynOrError(CelProtoTypes.typeToCelType(type)); } /** Tests whether the type has error or dyn kind. Both have the property to match any type. */ @@ -238,18 +238,18 @@ public static CelType mostGeneral(CelType type1, CelType type2) { subs.entrySet().stream() .collect( Collectors.toMap( - k -> CelTypes.typeToCelType(k.getKey()), - v -> CelTypes.typeToCelType(v.getValue()), + k -> CelProtoTypes.typeToCelType(k.getKey()), + v -> CelProtoTypes.typeToCelType(v.getValue()), (prev, next) -> next, HashMap::new)); if (internalIsAssignable( - subsCopy, CelTypes.typeToCelType(type1), CelTypes.typeToCelType(type2))) { + subsCopy, CelProtoTypes.typeToCelType(type1), CelProtoTypes.typeToCelType(type2))) { return subsCopy.entrySet().stream() .collect( Collectors.toMap( - k -> CelTypes.celTypeToType(k.getKey()), - v -> CelTypes.celTypeToType(v.getValue()), + k -> CelProtoTypes.celTypeToType(k.getKey()), + v -> CelProtoTypes.celTypeToType(v.getValue()), (prev, next) -> next, HashMap::new)); } @@ -384,7 +384,8 @@ private static boolean isAssignableFromNull(CelType targetType) { */ @Deprecated public static boolean isEqualOrLessSpecific(Type type1, Type type2) { - return isEqualOrLessSpecific(CelTypes.typeToCelType(type1), CelTypes.typeToCelType(type2)); + return isEqualOrLessSpecific( + CelProtoTypes.typeToCelType(type1), CelProtoTypes.typeToCelType(type2)); } /** @@ -426,7 +427,7 @@ public static boolean isEqualOrLessSpecific(CelType type1, CelType type2) { TypeType typeType2 = (TypeType) type2; return isEqualOrLessSpecific(typeType1.type(), typeType2.type()); - // Message, primitive, well-known, and wrapper type names must be equal to be equivalent. + // Message, primitive, well-known, and wrapper type names must be equal to be equivalent. default: return type1.equals(type2); } @@ -493,10 +494,11 @@ private static boolean notReferencedIn( public static Type substitute(Map subs, Type type, boolean typeParamToDyn) { ImmutableMap.Builder subsMap = ImmutableMap.builder(); for (Map.Entry sub : subs.entrySet()) { - subsMap.put(CelTypes.typeToCelType(sub.getKey()), CelTypes.typeToCelType(sub.getValue())); + subsMap.put( + CelProtoTypes.typeToCelType(sub.getKey()), CelProtoTypes.typeToCelType(sub.getValue())); } - return CelTypes.celTypeToType( - substitute(subsMap.buildOrThrow(), CelTypes.typeToCelType(type), typeParamToDyn)); + return CelProtoTypes.celTypeToType( + substitute(subsMap.buildOrThrow(), CelProtoTypes.typeToCelType(type), typeParamToDyn)); } /** diff --git a/checker/src/test/java/dev/cel/checker/BUILD.bazel b/checker/src/test/java/dev/cel/checker/BUILD.bazel index e3e410429..51daf6cbf 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", @@ -20,17 +19,19 @@ java_library( "//checker:checker_legacy_environment", "//checker:proto_expr_visitor", "//checker:proto_type_mask", + "//checker:standard_decl", "//checker:type_inferencer", "//checker:type_provider_legacy_impl", "//common", "//common:compiler_common", + "//common:options", "//common:proto_ast", "//common/ast", "//common/internal:env_visitor", "//common/internal:errors", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:json", "//common/types:message_type_provider", "//common/types:type_providers", @@ -40,16 +41,16 @@ java_library( "//parser:operator", "//testing:adorner", "//testing:cel_baseline_test_case", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:org_jspecify_jspecify", "@maven//:junit_junit", + "@maven//:com_google_testparameterinjector_test_parameter_injector", "//: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", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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", ], ) diff --git a/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java b/checker/src/test/java/dev/cel/checker/CelCheckerLegacyImplTest.java index 4e0c15576..a19770c6a 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.expr.conformance.proto3.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("google.api.expr.test.v1.proto3.TestAllTypes")) + ProtoTypeMask.ofAllFields("cel.expr.conformance.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("google.api.expr.test.v1.proto3.TestAllTypes")); + ProtoTypeMask.ofAllFields("cel.expr.conformance.proto3.TestAllTypes")); celCheckerBuilder.addLibraries(new CelCheckerLibrary() {}); assertThat(newCheckerBuilder.getFunctionDecls().build()).isEmpty(); diff --git a/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java b/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java index f78a4fa62..0dd7d83df 100644 --- a/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java +++ b/checker/src/test/java/dev/cel/checker/CelOverloadDeclTest.java @@ -22,7 +22,7 @@ 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.CelProtoTypes; import dev.cel.common.types.SimpleType; import dev.cel.common.types.TypeParamType; import org.junit.Test; @@ -81,9 +81,10 @@ public void toProtoOverload_withTypeParams() { Overload protoOverload = CelOverloadDecl.celOverloadToOverload(celOverloadDecl); assertThat(protoOverload.getOverloadId()).isEqualTo("overloadId"); assertThat(protoOverload.getIsInstanceFunction()).isTrue(); - assertThat(protoOverload.getResultType()).isEqualTo(CelTypes.createTypeParam("A")); + assertThat(protoOverload.getResultType()).isEqualTo(CelProtoTypes.createTypeParam("A")); assertThat(protoOverload.getParamsList()) - .containsExactly(CelTypes.STRING, CelTypes.DOUBLE, CelTypes.createTypeParam("B")); + .containsExactly( + CelProtoTypes.STRING, CelProtoTypes.DOUBLE, CelProtoTypes.createTypeParam("B")); assertThat(protoOverload.getTypeParamsList()).containsExactly("A", "B"); } diff --git a/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java b/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java index 3b598d4c7..37e734853 100644 --- a/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java +++ b/checker/src/test/java/dev/cel/checker/CelProtoExprVisitorTest.java @@ -19,12 +19,12 @@ 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; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; import java.util.Optional; diff --git a/checker/src/test/java/dev/cel/checker/CelStandardDeclarationsTest.java b/checker/src/test/java/dev/cel/checker/CelStandardDeclarationsTest.java new file mode 100644 index 000000000..17a7212a1 --- /dev/null +++ b/checker/src/test/java/dev/cel/checker/CelStandardDeclarationsTest.java @@ -0,0 +1,275 @@ +// 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 static dev.cel.common.CelFunctionDecl.newFunctionDeclaration; +import static org.junit.Assert.assertThrows; + +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.checker.CelStandardDeclarations.StandardFunction; +import dev.cel.checker.CelStandardDeclarations.StandardFunction.Overload.Arithmetic; +import dev.cel.checker.CelStandardDeclarations.StandardIdentifier; +import dev.cel.common.CelOptions; +import dev.cel.common.CelValidationException; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelStandardDeclarationsTest { + + @Test + @TestParameters("{includeFunction: true, excludeFunction: true, filterFunction: true}") + @TestParameters("{includeFunction: true, excludeFunction: true, filterFunction: false}") + @TestParameters("{includeFunction: true, excludeFunction: false, filterFunction: true}") + @TestParameters("{includeFunction: false, excludeFunction: true, filterFunction: true}") + public void standardDeclaration_moreThanOneFunctionFilterSet_throws( + boolean includeFunction, boolean excludeFunction, boolean filterFunction) { + CelStandardDeclarations.Builder builder = CelStandardDeclarations.newBuilder(); + if (includeFunction) { + builder.includeFunctions(StandardFunction.ADD); + } + if (excludeFunction) { + builder.excludeFunctions(StandardFunction.SUBTRACT); + } + if (filterFunction) { + builder.filterFunctions((func, over) -> true); + } + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, builder::build); + assertThat(e) + .hasMessageThat() + .contains( + "You may only populate one of the following builder methods: includeFunctions," + + " excludeFunctions or filterFunctions"); + } + + @Test + @TestParameters("{includeIdentifier: true, excludeIdentifier: true, filterIdentifier: true}") + @TestParameters("{includeIdentifier: true, excludeIdentifier: true, filterIdentifier: false}") + @TestParameters("{includeIdentifier: true, excludeIdentifier: false, filterIdentifier: true}") + @TestParameters("{includeIdentifier: false, excludeIdentifier: true, filterIdentifier: true}") + public void standardDeclaration_moreThanOneIdentifierFilterSet_throws( + boolean includeIdentifier, boolean excludeIdentifier, boolean filterIdentifier) { + CelStandardDeclarations.Builder builder = CelStandardDeclarations.newBuilder(); + if (includeIdentifier) { + builder.includeIdentifiers(StandardIdentifier.MAP); + } + if (excludeIdentifier) { + builder.excludeIdentifiers(StandardIdentifier.BOOL); + } + if (filterIdentifier) { + builder.filterIdentifiers((ident) -> true); + } + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, builder::build); + assertThat(e) + .hasMessageThat() + .contains( + "You may only populate one of the following builder methods: includeIdentifiers," + + " excludeIdentifiers or filterIdentifiers"); + } + + @Test + public void compiler_standardEnvironmentEnabled_throwsWhenOverridingDeclarations() { + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardEnvironmentEnabled(true) + .setStandardDeclarations( + CelStandardDeclarations.newBuilder() + .includeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build()) + .build()); + + assertThat(e) + .hasMessageThat() + .contains( + "setStandardEnvironmentEnabled must be set to false to override standard" + + " declarations."); + } + + @Test + public void standardDeclarations_includeFunctions() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .includeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build(); + + assertThat(celStandardDeclaration.functionDecls()) + .containsExactly( + StandardFunction.ADD.functionDecl(), StandardFunction.SUBTRACT.functionDecl()); + } + + @Test + public void standardDeclarations_excludeFunctions() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .excludeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build(); + + assertThat(celStandardDeclaration.functionDecls()) + .doesNotContain(StandardFunction.ADD.functionDecl()); + assertThat(celStandardDeclaration.functionDecls()) + .doesNotContain(StandardFunction.SUBTRACT.functionDecl()); + } + + @Test + public void standardDeclarations_filterFunctions() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .filterFunctions( + (func, over) -> { + if (func.equals(StandardFunction.ADD) && over.equals(Arithmetic.ADD_INT64)) { + return true; + } + + if (func.equals(StandardFunction.SUBTRACT) + && over.equals(Arithmetic.SUBTRACT_INT64)) { + return true; + } + + return false; + }) + .build(); + + assertThat(celStandardDeclaration.functionDecls()) + .containsExactly( + newFunctionDeclaration( + StandardFunction.ADD.functionName(), Arithmetic.ADD_INT64.celOverloadDecl()), + newFunctionDeclaration( + StandardFunction.SUBTRACT.functionName(), + Arithmetic.SUBTRACT_INT64.celOverloadDecl())); + } + + @Test + public void standardDeclarations_includeIdentifiers() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .includeIdentifiers(StandardIdentifier.INT, StandardIdentifier.UINT) + .build(); + + assertThat(celStandardDeclaration.identifierDecls()) + .containsExactly(StandardIdentifier.INT.identDecl(), StandardIdentifier.UINT.identDecl()); + } + + @Test + public void standardDeclarations_excludeIdentifiers() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .excludeIdentifiers(StandardIdentifier.INT, StandardIdentifier.UINT) + .build(); + + assertThat(celStandardDeclaration.identifierDecls()) + .doesNotContain(StandardIdentifier.INT.identDecl()); + assertThat(celStandardDeclaration.identifierDecls()) + .doesNotContain(StandardIdentifier.UINT.identDecl()); + } + + @Test + public void standardDeclarations_filterIdentifiers() { + CelStandardDeclarations celStandardDeclaration = + CelStandardDeclarations.newBuilder() + .filterIdentifiers(ident -> ident.equals(StandardIdentifier.MAP)) + .build(); + + assertThat(celStandardDeclaration.identifierDecls()) + .containsExactly(StandardIdentifier.MAP.identDecl()); + } + + @Test + public void standardEnvironment_subsetEnvironment() throws Exception { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setStandardEnvironmentEnabled(false) + .setStandardDeclarations( + CelStandardDeclarations.newBuilder() + .includeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build()) + .build(); + + assertThat(celCompiler.compile("1 + 2 - 3").getAst()).isNotNull(); + CelValidationException e = + assertThrows(CelValidationException.class, () -> celCompiler.compile("1 * 2 / 3").getAst()); + assertThat(e).hasMessageThat().contains("undeclared reference to '_*_'"); + assertThat(e).hasMessageThat().contains("undeclared reference to '_/_'"); + } + + @Test + @TestParameters("{expression: '1 > 2.0'}") + @TestParameters("{expression: '2.0 > 1'}") + @TestParameters("{expression: '1 > 2u'}") + @TestParameters("{expression: '2u > 1'}") + @TestParameters("{expression: '2u > 1.0'}") + @TestParameters("{expression: '1.0 > 2u'}") + @TestParameters("{expression: '1 >= 2.0'}") + @TestParameters("{expression: '2.0 >= 1'}") + @TestParameters("{expression: '1 >= 2u'}") + @TestParameters("{expression: '2u >= 1'}") + @TestParameters("{expression: '2u >= 1.0'}") + @TestParameters("{expression: '1.0 >= 2u'}") + @TestParameters("{expression: '1 < 2.0'}") + @TestParameters("{expression: '2.0 < 1'}") + @TestParameters("{expression: '1 < 2u'}") + @TestParameters("{expression: '2u < 1'}") + @TestParameters("{expression: '2u < 1.0'}") + @TestParameters("{expression: '1.0 < 2u'}") + @TestParameters("{expression: '1 <= 2.0'}") + @TestParameters("{expression: '2.0 <= 1'}") + @TestParameters("{expression: '1 <= 2u'}") + @TestParameters("{expression: '2u <= 1'}") + @TestParameters("{expression: '2u <= 1.0'}") + @TestParameters("{expression: '1.0 <= 2u'}") + public void heterogeneousEqualityDisabled_mixedTypeComparisons_throws(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHeterogeneousNumericComparisons(false).build()) + .build(); + + CelValidationException e = + assertThrows(CelValidationException.class, () -> celCompiler.compile(expression).getAst()); + assertThat(e).hasMessageThat().contains("found no matching overload for"); + } + + @Test + public void unsignedLongsDisabled_int64Identity_throws() { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableUnsignedLongs(false).build()) + .build(); + + CelValidationException e = + assertThrows(CelValidationException.class, () -> celCompiler.compile("int(1)").getAst()); + assertThat(e).hasMessageThat().contains("found no matching overload for"); + } + + @Test + public void timestampEpochDisabled_int64Identity_throws() { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableTimestampEpoch(false).build()) + .build(); + + CelValidationException e = + assertThrows( + CelValidationException.class, () -> celCompiler.compile("timestamp(10000)").getAst()); + assertThat(e).hasMessageThat().contains("found no matching overload for"); + } +} diff --git a/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java b/checker/src/test/java/dev/cel/checker/DescriptorTypeProviderTest.java index 46e3a419d..11366a68b 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.common.types.CelProtoTypes; +import dev.cel.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import java.util.Arrays; import org.junit.Assert; import org.junit.Test; @@ -36,7 +36,7 @@ public final class DescriptorTypeProviderTest { @Test public void lookupFieldNames_nonMessageType() { TypeProvider typeProvider = new DescriptorTypeProvider(); - assertThat(typeProvider.lookupFieldNames(CelTypes.STRING)).isNull(); + assertThat(typeProvider.lookupFieldNames(CelProtoTypes.STRING)).isNull(); } @Test @@ -44,20 +44,21 @@ public void lookupFieldNames_undeclaredMessageType() { TypeProvider typeProvider = new DescriptorTypeProvider(); assertThat( typeProvider.lookupFieldNames( - CelTypes.createMessage("google.rpc.context.AttributeContext"))) + CelProtoTypes.createMessage("google.rpc.context.AttributeContext"))) .isNull(); } @Test public void lookupFieldNames_groupTypeField() throws Exception { - Type proto2MessageType = CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"); + Type proto2MessageType = + CelProtoTypes.createMessage("cel.expr.conformance.proto2.TestAllTypes"); TypeProvider typeProvider = new DescriptorTypeProvider( ImmutableList.of( TestAllTypes.getDescriptor().getFile(), TestAllTypesExtensions.getDescriptor())); assertThat(typeProvider.lookupFieldType(proto2MessageType, "nestedgroup").type()) .isEqualTo( - CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup")); + CelProtoTypes.createMessage("cel.expr.conformance.proto2.TestAllTypes.NestedGroup")); } @Test @@ -100,35 +101,36 @@ public void lookupExtensionType_combinedProvider() { makePartialTypeProvider(configuredProvider); final TypeProvider typeProvider = new CombinedTypeProvider(ImmutableList.of(partialProvider, configuredProvider)); - final Type messageType = CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"); + final Type messageType = + CelProtoTypes.createMessage("cel.expr.conformance.proto2.TestAllTypes"); assertThat(typeProvider.lookupExtensionType("non.existent")).isNull(); ExtensionFieldType nestedExt = - typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.nested_ext"); + typeProvider.lookupExtensionType("cel.expr.conformance.proto2.nested_ext"); assertThat(nestedExt).isNotNull(); assertThat(nestedExt.fieldType().type()).isEqualTo(messageType); assertThat(nestedExt.messageType()).isEqualTo(messageType); ExtensionFieldType int32Ext = - typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.int32_ext"); + typeProvider.lookupExtensionType("cel.expr.conformance.proto2.int32_ext"); assertThat(int32Ext).isNotNull(); - assertThat(int32Ext.fieldType().type()).isEqualTo(CelTypes.INT64); + assertThat(int32Ext.fieldType().type()).isEqualTo(CelProtoTypes.INT64); assertThat(int32Ext.messageType()).isEqualTo(messageType); ExtensionFieldType repeatedExt = - typeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.repeated_test_all_types"); + typeProvider.lookupExtensionType("cel.expr.conformance.proto2.repeated_test_all_types"); assertThat(repeatedExt).isNotNull(); assertThat(repeatedExt.fieldType().type()) .isEqualTo( - CelTypes.createList( - CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes"))); + CelProtoTypes.createList( + CelProtoTypes.createMessage("cel.expr.conformance.proto2.TestAllTypes"))); assertThat(repeatedExt.messageType()).isEqualTo(messageType); // With leading dot '.'. assertThat( typeProvider.lookupExtensionType( - ".google.api.expr.test.v1.proto2.repeated_test_all_types")) + ".cel.expr.conformance.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 c232441fc..b2ecd5a73 100644 --- a/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java +++ b/checker/src/test/java/dev/cel/checker/ExprCheckerTest.java @@ -14,13 +14,13 @@ package dev.cel.checker; -import static dev.cel.common.types.CelTypes.createList; -import static dev.cel.common.types.CelTypes.createMap; -import static dev.cel.common.types.CelTypes.createMessage; -import static dev.cel.common.types.CelTypes.createOptionalType; -import static dev.cel.common.types.CelTypes.createTypeParam; -import static dev.cel.common.types.CelTypes.createWrapper; -import static dev.cel.common.types.CelTypes.format; +import static dev.cel.common.types.CelProtoTypes.createList; +import static dev.cel.common.types.CelProtoTypes.createMap; +import static dev.cel.common.types.CelProtoTypes.createMessage; +import static dev.cel.common.types.CelProtoTypes.createOptionalType; +import static dev.cel.common.types.CelProtoTypes.createTypeParam; +import static dev.cel.common.types.CelProtoTypes.createWrapper; +import static dev.cel.common.types.CelProtoTypes.format; import dev.cel.expr.CheckedExpr; import dev.cel.expr.Constant; @@ -31,8 +31,6 @@ 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; @@ -42,11 +40,12 @@ import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.internal.EnvVisitable; import dev.cel.common.internal.Errors; -import dev.cel.common.types.CelTypes; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.ProtoMessageTypeProvider; import dev.cel.common.types.SimpleType; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.testing.CelAdorner; import dev.cel.testing.CelBaselineTestCase; import dev.cel.testing.CelDebug; @@ -76,7 +75,8 @@ private void runTest() throws Exception { CelAbstractSyntaxTree ast = prepareTest( Arrays.asList( - TestAllTypes.getDescriptor(), TestAllTypesProto.TestAllTypes.getDescriptor())); + TestAllTypes.getDescriptor(), + dev.cel.expr.conformance.proto2.TestAllTypes.getDescriptor())); if (ast != null) { testOutput() .println( @@ -152,7 +152,7 @@ public void operatorsBytes() throws Exception { @Test public void operatorsConditional() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "false ? x.single_timestamp : null"; runTest(); } @@ -163,19 +163,19 @@ public void operatorsConditional() throws Exception { @Test public void referenceTypeRelative() throws Exception { source = "proto3.TestAllTypes"; - container = "google.api.expr.test.v1.TestAllTypes"; + container = "cel.expr.conformance.TestAllTypes"; runTest(); } @Test public void referenceTypeAbsolute() throws Exception { - source = ".google.api.expr.test.v1.proto3.TestAllTypes"; + source = ".cel.expr.conformance.proto3.TestAllTypes"; runTest(); } @Test public void referenceValue() throws Exception { - declareVariable("container.x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("container.x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x"; container = "container"; runTest(); @@ -192,19 +192,19 @@ public void referenceUndefinedError() throws Exception { @Test public void anyMessage() throws Exception { - declareVariable("x", CelTypes.ANY); + declareVariable("x", CelProtoTypes.ANY); declareVariable("y", createWrapper(PrimitiveType.INT64)); source = "x == google.protobuf.Any{" - + "type_url:'types.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes'}" + + "type_url:'types.googleapis.com/cel.expr.conformance.proto3.TestAllTypes'}" + " && x.single_nested_message.bb == 43 || x ==" - + " google.api.expr.test.v1.proto3.TestAllTypes{} || y < x|| x >= x"; + + " cel.expr.conformance.proto3.TestAllTypes{} || y < x|| x >= x"; runTest(); } @Test public void messageFieldSelect() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.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)"; @@ -213,7 +213,7 @@ public void messageFieldSelect() throws Exception { @Test public void messageFieldSelectError() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_nested_message.undefined == x.undefined"; runTest(); } @@ -223,7 +223,7 @@ public void messageFieldSelectError() throws Exception { @Test public void listOperators() throws Exception { - declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); + declareVariable("x", createList(createMessage("cel.expr.conformance.proto3.TestAllTypes"))); source = "(x + x)[1].single_int32 == size(x)"; runTest(); @@ -233,14 +233,14 @@ public void listOperators() throws Exception { @Test public void listRepeatedOperators() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.repeated_int64[x.single_int32] == 23"; runTest(); } @Test public void listIndexTypeError() throws Exception { - declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); + declareVariable("x", createList(createMessage("cel.expr.conformance.proto3.TestAllTypes"))); source = "x[1u]"; runTest(); } @@ -253,8 +253,8 @@ public void identError() throws Exception { @Test public void listElemTypeError() throws Exception { - declareVariable("x", createList(createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); - declareVariable("y", createList(CelTypes.INT64)); + declareVariable("x", createList(createMessage("cel.expr.conformance.proto3.TestAllTypes"))); + declareVariable("y", createList(CelProtoTypes.INT64)); source = "x + y"; runTest(); } @@ -266,7 +266,7 @@ public void listElemTypeError() throws Exception { public void mapOperators() throws Exception { declareVariable( "x", - createMap(CelTypes.STRING, createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); + createMap(CelProtoTypes.STRING, createMessage("cel.expr.conformance.proto3.TestAllTypes"))); source = "x[\"a\"].single_int32 == 23"; runTest(); @@ -278,14 +278,14 @@ public void mapOperators() throws Exception { public void mapIndexTypeError() throws Exception { declareVariable( "x", - createMap(CelTypes.STRING, createMessage("google.api.expr.test.v1.proto3.TestAllTypes"))); + createMap(CelProtoTypes.STRING, createMessage("cel.expr.conformance.proto3.TestAllTypes"))); source = "x[2].single_int32 == 23"; runTest(); } @Test public void mapEmpty() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "size(x.map_int64_nested_type) == 0"; runTest(); } @@ -295,14 +295,14 @@ public void mapEmpty() throws Exception { @Test public void wrapper() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_int64_wrapper + 1 != 23"; runTest(); } @Test public void equalsWrapper() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_int64_wrapper == 1 && " + "x.single_int32_wrapper != 2 && " @@ -318,18 +318,18 @@ public void equalsWrapper() throws Exception { @Test public void nullableWrapper() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_int64_wrapper == null"; runTest(); } @Test public void nullableMessage() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_nested_message != null"; runTest(); - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3.TestAllTypesProto"; source = "null == TestAllTypes{} || TestAllTypes{} == null"; runTest(); } @@ -342,7 +342,7 @@ public void nullNull() throws Exception { @Test public void nullablePrimitiveError() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_int64 != null"; runTest(); } @@ -352,14 +352,14 @@ public void nullablePrimitiveError() throws Exception { @Test public void dynOperators() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_value + 1 / x.single_struct.y == 23"; runTest(); } @Test public void dynOperatorsAtRuntime() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto3.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto3.TestAllTypes")); source = "x.single_value[23] + x.single_struct['y']"; runTest(); } @@ -424,8 +424,11 @@ public void callStyle() throws Exception { declareFunction( "size", memberOverload( - "my_size", ImmutableList.of(createList(param)), ImmutableList.of("A"), CelTypes.INT64)); - declareVariable("x", createList(CelTypes.INT64)); + "my_size", + ImmutableList.of(createList(param)), + ImmutableList.of("A"), + CelProtoTypes.INT64)); + declareVariable("x", createList(CelProtoTypes.INT64)); source = "size(x) == x.size()"; runTest(); } @@ -436,12 +439,12 @@ public void userFunction() throws Exception { "myfun", memberOverload( "myfun_instance", - ImmutableList.of(CelTypes.INT64, CelTypes.BOOL, CelTypes.UINT64), - CelTypes.INT64), + ImmutableList.of(CelProtoTypes.INT64, CelProtoTypes.BOOL, CelProtoTypes.UINT64), + CelProtoTypes.INT64), globalOverload( "myfun_static", - ImmutableList.of(CelTypes.INT64, CelTypes.BOOL, CelTypes.UINT64), - CelTypes.INT64)); + ImmutableList.of(CelProtoTypes.INT64, CelProtoTypes.BOOL, CelProtoTypes.UINT64), + CelProtoTypes.INT64)); source = "myfun(1, true, 3u) + 1.myfun(false, 3u).myfun(true, 42u)"; runTest(); } @@ -450,7 +453,8 @@ public void userFunction() throws Exception { public void namespacedFunctions() throws Exception { declareFunction( "ns.func", - globalOverload("ns_func_overload", ImmutableList.of(CelTypes.STRING), CelTypes.INT64)); + globalOverload( + "ns_func_overload", ImmutableList.of(CelProtoTypes.STRING), CelProtoTypes.INT64)); source = "ns.func('hello')"; runTest(); @@ -458,8 +462,8 @@ public void namespacedFunctions() throws Exception { "member", memberOverload( "ns_member_overload", - ImmutableList.of(CelTypes.INT64, CelTypes.INT64), - CelTypes.INT64)); + ImmutableList.of(CelProtoTypes.INT64, CelProtoTypes.INT64), + CelProtoTypes.INT64)); source = "ns.func('hello').member(ns.func('test'))"; runTest(); @@ -490,13 +494,13 @@ public void namespacedFunctions() throws Exception { @Test public void namespacedVariables() throws Exception { container = "ns"; - declareVariable("ns.x", CelTypes.INT64); + declareVariable("ns.x", CelProtoTypes.INT64); source = "x"; runTest(); - 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); + container = "cel.expr.conformance.proto3"; + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); + declareVariable("cel.expr.conformance.proto3.msgVar", messageType); source = "msgVar.single_int32"; runTest(); } @@ -507,8 +511,8 @@ public void userFunctionMultipleOverloadsWithSanitization() throws Exception { declareVariable("s", structType); declareFunction( "myfun", - globalOverload("myfun_int", ImmutableList.of(CelTypes.INT64), CelTypes.INT64), - globalOverload("myfun_struct", ImmutableList.of(structType), CelTypes.INT64)); + globalOverload("myfun_int", ImmutableList.of(CelProtoTypes.INT64), CelProtoTypes.INT64), + globalOverload("myfun_struct", ImmutableList.of(structType), CelProtoTypes.INT64)); source = "myfun(1) + myfun(s)"; runTest(); } @@ -525,25 +529,26 @@ public void userFunctionOverlaps() throws Exception { "my_size", ImmutableList.of(createList(param)), ImmutableList.of("TEST"), - CelTypes.UINT64)); - declareVariable("x", createList(CelTypes.INT64)); + CelProtoTypes.UINT64)); + declareVariable("x", createList(CelProtoTypes.INT64)); source = "size(x) == 1u"; runTest(); } @Test public void userFunctionAddsOverload() throws Exception { - Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("x", messageType); declareFunction( - "size", globalOverload("size_message", ImmutableList.of(messageType), CelTypes.INT64)); + "size", globalOverload("size_message", ImmutableList.of(messageType), CelProtoTypes.INT64)); source = "size(x) > 4"; runTest(); } @Test public void userFunctionAddsMacroError() throws Exception { - declareFunction("has", globalOverload("has_id", ImmutableList.of(CelTypes.DYN), CelTypes.DYN)); + declareFunction( + "has", globalOverload("has_id", ImmutableList.of(CelProtoTypes.DYN), CelProtoTypes.DYN)); source = "false"; runTest(); } @@ -553,7 +558,7 @@ public void userFunctionAddsMacroError() throws Exception { @Test public void proto2PrimitiveField() throws Exception { - declareVariable("x", createMessage("google.api.expr.test.v1.proto2.TestAllTypes")); + declareVariable("x", createMessage("cel.expr.conformance.proto2.TestAllTypes")); source = "x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null"; runTest(); source = "x.nestedgroup.single_name == ''"; @@ -565,21 +570,21 @@ public void proto2PrimitiveField() throws Exception { @Test public void aggregateMessage() throws Exception { - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes{single_int32: 1, single_int64: 2}"; runTest(); } @Test public void aggregateMessageFieldUndefinedError() throws Exception { - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes{single_int32: 1, undefined: 2}"; runTest(); } @Test public void aggregateMessageFieldTypeError() throws Exception { - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes{single_int32: 1u}"; runTest(); } @@ -663,7 +668,7 @@ public void types() throws Exception { @Test public void enumValues() throws Exception { - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes.NestedEnum.BAR != 99"; runTest(); } @@ -675,7 +680,7 @@ public void nestedEnums() throws Exception { source = "x.single_nested_enum == TestAllTypes.NestedEnum.BAR"; runTest(); - declareVariable("single_nested_enum", CelTypes.INT64); + declareVariable("single_nested_enum", CelProtoTypes.INT64); source = "single_nested_enum == TestAllTypes.NestedEnum.BAR"; runTest(); @@ -686,7 +691,7 @@ public void nestedEnums() throws Exception { @Test public void globalEnumValues() throws Exception { - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "GlobalEnum.GAZ == 2"; runTest(); } @@ -696,7 +701,7 @@ public void globalEnumValues() throws Exception { @Test public void globalStandaloneEnumValues() throws Exception { - container = "dev.cel.testing.testdata.proto3.TestAllTypesProto"; + container = "dev.cel.testing.testdata.proto3"; source = "StandaloneGlobalEnum.SGAZ == 2"; FileDescriptorSet.Builder descriptorBuilder = FileDescriptorSet.newBuilder(); @@ -726,7 +731,7 @@ public void conversions() throws Exception { @Test public void quantifiers() throws Exception { - Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.all(e, e > 0) " @@ -737,7 +742,7 @@ public void quantifiers() throws Exception { @Test public void quantifiersErrors() throws Exception { - Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.all(e, 0)"; runTest(); @@ -745,7 +750,7 @@ public void quantifiersErrors() throws Exception { @Test public void mapExpr() throws Exception { - Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.map(x, double(x))"; runTest(); @@ -759,16 +764,16 @@ public void mapExpr() throws Exception { @Test public void mapFilterExpr() throws Exception { - Type messageType = createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("x", messageType); source = "x.repeated_int64.map(x, x > 0, double(x))"; runTest(); - declareVariable("lists", CelTypes.DYN); + declareVariable("lists", CelProtoTypes.DYN); source = "lists.filter(x, x > 1.5)"; runTest(); - declareVariable("args", createMap(CelTypes.STRING, CelTypes.DYN)); + declareVariable("args", createMap(CelProtoTypes.STRING, CelProtoTypes.DYN)); source = "args.user[\"myextension\"].customAttributes.filter(x, x.name == \"hobbies\")"; runTest(); } @@ -781,12 +786,12 @@ public void abstractTypeParameterLess() throws Exception { Type abstractType = Type.newBuilder().setAbstractType(AbstractType.newBuilder().setName("abs")).build(); // Declare the identifier 'abs' to bind to the abstract type. - declareVariable("abs", CelTypes.create(abstractType)); + declareVariable("abs", CelProtoTypes.create(abstractType)); // Declare a function to create a new value of abstract type. declareFunction("make_abs", globalOverload("make_abs", ImmutableList.of(), abstractType)); // Declare a function to consume value of abstract type. declareFunction( - "as_bool", memberOverload("as_bool", ImmutableList.of(abstractType), CelTypes.BOOL)); + "as_bool", memberOverload("as_bool", ImmutableList.of(abstractType), CelProtoTypes.BOOL)); source = "type(make_abs()) == abs && make_abs().as_bool()"; runTest(); @@ -794,7 +799,7 @@ public void abstractTypeParameterLess() throws Exception { @Test public void abstractTypeParameterized() throws Exception { - Type typeParam = createTypeParam("T"); + Type typeParam = CelProtoTypes.createTypeParam("T"); Type abstractType = Type.newBuilder() .setAbstractType( @@ -805,14 +810,14 @@ public void abstractTypeParameterized() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", - ImmutableList.of(CelTypes.create(typeParam)), + "vector_type", + ImmutableList.of(CelProtoTypes.create(typeParam)), ImmutableList.of("T"), - CelTypes.create(abstractType)), + CelProtoTypes.create(abstractType)), // Declare a function to create a new value of abstract type based on a list. globalOverload( - "vector", - ImmutableList.of(createList(typeParam)), + "vector_list", + ImmutableList.of(CelProtoTypes.createList(typeParam)), ImmutableList.of("T"), abstractType)); @@ -820,8 +825,8 @@ public void abstractTypeParameterized() throws Exception { declareFunction( "at", memberOverload( - "at", - ImmutableList.of(abstractType, CelTypes.INT64), + "vector_at_int", + ImmutableList.of(abstractType, CelProtoTypes.INT64), ImmutableList.of("T"), typeParam)); @@ -843,13 +848,13 @@ public void abstractTypeParameterizedInListLiteral() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", - ImmutableList.of(CelTypes.create(typeParam)), + "vector_type", + ImmutableList.of(CelProtoTypes.create(typeParam)), ImmutableList.of("T"), - CelTypes.create(abstractType)), + CelProtoTypes.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 +875,24 @@ public void abstractTypeParameterizedError() throws Exception { "vector", // Declare the function 'vector' to create the abstract type. globalOverload( - "vector", - ImmutableList.of(CelTypes.create(typeParam)), + "vector_type", + ImmutableList.of(CelProtoTypes.create(typeParam)), ImmutableList.of("T"), - CelTypes.create(abstractType)), + CelProtoTypes.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", - ImmutableList.of(CelTypes.create(abstractType), CelTypes.create(abstractType)), + "add_vector_type", + ImmutableList.of( + CelProtoTypes.create(abstractType), CelProtoTypes.create(abstractType)), ImmutableList.of("T"), - abstractType)); + CelProtoTypes.create(abstractType))); source = "add(vector([1, 2]), vector([2u, -1])) == vector([1, 2, 2u, -1])"; runTest(); } @@ -894,12 +900,12 @@ public void abstractTypeParameterizedError() throws Exception { // Optionals @Test public void optionals() throws Exception { - declareVariable("a", createMap(CelTypes.STRING, CelTypes.STRING)); + declareVariable("a", createMap(CelProtoTypes.STRING, CelProtoTypes.STRING)); source = "a.?b"; runTest(); clearAllDeclarations(); - declareVariable("x", createOptionalType(createMap(CelTypes.STRING, CelTypes.STRING))); + declareVariable("x", createOptionalType(createMap(CelProtoTypes.STRING, CelProtoTypes.STRING))); source = "x.y"; runTest(); @@ -907,7 +913,7 @@ public void optionals() throws Exception { runTest(); clearAllDeclarations(); - declareVariable("d", createOptionalType(CelTypes.DYN)); + declareVariable("d", createOptionalType(CelProtoTypes.DYN)); source = "d.dynamic"; runTest(); @@ -915,7 +921,7 @@ public void optionals() throws Exception { runTest(); clearAllDeclarations(); - declareVariable("e", createOptionalType(createMap(CelTypes.STRING, CelTypes.DYN))); + declareVariable("e", createOptionalType(createMap(CelProtoTypes.STRING, CelProtoTypes.DYN))); source = "has(e.?b.c)"; runTest(); @@ -926,13 +932,13 @@ public void optionals() throws Exception { source = "{?'key': {'a': 'b'}.?value}.key"; runTest(); - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes{?single_int32: {}.?i}"; runTest(); container = ""; - declareVariable("a", createOptionalType(CelTypes.STRING)); - declareVariable("b", createOptionalType(CelTypes.STRING)); + declareVariable("a", createOptionalType(CelProtoTypes.STRING)); + declareVariable("b", createOptionalType(CelProtoTypes.STRING)); source = "[?a, ?b, 'world']"; runTest(); @@ -951,12 +957,12 @@ public void optionalErrors() throws Exception { source = "[?'value']"; runTest(); - container = "google.api.expr.test.v1.proto3.TestAllTypesProto"; + container = "cel.expr.conformance.proto3"; source = "TestAllTypes{?single_int32: 1}"; runTest(); source = "a.?b"; - declareVariable("a", createMap(CelTypes.STRING, CelTypes.STRING)); + declareVariable("a", createMap(CelProtoTypes.STRING, CelProtoTypes.STRING)); prepareCompiler(new ProtoMessageTypeProvider()); ParsedExpr parsedExpr = CelProtoAbstractSyntaxTree.fromCelAst(celCompiler.parse(source).getAst()).toParsedExpr(); diff --git a/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java b/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java index 9195bb3d5..4569877c3 100644 --- a/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java +++ b/checker/src/test/java/dev/cel/checker/TypeProviderLegacyImplTest.java @@ -18,13 +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.CelProtoTypes; import dev.cel.common.types.ProtoMessageTypeProvider; +import dev.cel.expr.conformance.proto2.Proto2ExtensionScopedMessage; +import dev.cel.expr.conformance.proto2.TestAllTypes; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -45,9 +45,8 @@ public final class TypeProviderLegacyImplTest { @Test public void lookupType() { - assertThat(compatTypeProvider.lookupType("google.api.expr.test.v1.proto2.TestAllTypes")) - .isEqualTo( - descriptorTypeProvider.lookupType("google.api.expr.test.v1.proto2.TestAllTypes")); + assertThat(compatTypeProvider.lookupType("cel.expr.conformance.proto2.TestAllTypes")) + .isEqualTo(descriptorTypeProvider.lookupType("cel.expr.conformance.proto2.TestAllTypes")); assertThat(compatTypeProvider.lookupType("not.registered.TypeName")) .isEqualTo(descriptorTypeProvider.lookupType("not.registered.TypeName")); } @@ -55,9 +54,7 @@ public void lookupType() { @Test public void lookupFieldNames() { Type nestedTestAllTypes = - compatTypeProvider - .lookupType("google.api.expr.test.v1.proto2.NestedTestAllTypes") - .getType(); + compatTypeProvider.lookupType("cel.expr.conformance.proto2.NestedTestAllTypes").getType(); ImmutableSet fieldNames = compatTypeProvider.lookupFieldNames(nestedTestAllTypes); assertThat(fieldNames) .containsExactlyElementsIn(descriptorTypeProvider.lookupFieldNames(nestedTestAllTypes)); @@ -67,9 +64,7 @@ public void lookupFieldNames() { @Test public void lookupFieldType() { Type nestedTestAllTypes = - compatTypeProvider - .lookupType("google.api.expr.test.v1.proto2.NestedTestAllTypes") - .getType(); + compatTypeProvider.lookupType("cel.expr.conformance.proto2.NestedTestAllTypes").getType(); assertThat(compatTypeProvider.lookupFieldType(nestedTestAllTypes, "payload")) .isEqualTo(descriptorTypeProvider.lookupFieldType(nestedTestAllTypes, "payload")); assertThat(compatTypeProvider.lookupFieldType(nestedTestAllTypes, "child")) @@ -79,7 +74,7 @@ public void lookupFieldType() { @Test public void lookupFieldType_inputNotMessage() { Type globalEnumType = - compatTypeProvider.lookupType("google.api.expr.test.v1.proto2.GlobalEnum").getType(); + compatTypeProvider.lookupType("cel.expr.conformance.proto2.GlobalEnum").getType(); assertThat(compatTypeProvider.lookupFieldType(globalEnumType, "payload")).isNull(); assertThat(compatTypeProvider.lookupFieldType(globalEnumType, "payload")) .isEqualTo(descriptorTypeProvider.lookupFieldType(globalEnumType, "payload")); @@ -88,47 +83,44 @@ public void lookupFieldType_inputNotMessage() { @Test public void lookupExtension() { TypeProvider.ExtensionFieldType extensionType = - compatTypeProvider.lookupExtensionType("google.api.expr.test.v1.proto2.nested_enum_ext"); + compatTypeProvider.lookupExtensionType("cel.expr.conformance.proto2.nested_enum_ext"); assertThat(extensionType.messageType()) - .isEqualTo(CelTypes.createMessage("google.api.expr.test.v1.proto2.TestAllTypes")); - assertThat(extensionType.fieldType().type()).isEqualTo(CelTypes.INT64); + .isEqualTo(CelProtoTypes.createMessage("cel.expr.conformance.proto2.TestAllTypes")); + assertThat(extensionType.fieldType().type()).isEqualTo(CelProtoTypes.INT64); assertThat(extensionType) .isEqualTo( descriptorTypeProvider.lookupExtensionType( - "google.api.expr.test.v1.proto2.nested_enum_ext")); + "cel.expr.conformance.proto2.nested_enum_ext")); } @Test public void lookupEnumValue() { Integer enumValue = - compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.GlobalEnum.GAR"); + compatTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.GlobalEnum.GAR"); assertThat(enumValue).isEqualTo(1); assertThat(enumValue) .isEqualTo( - descriptorTypeProvider.lookupEnumValue( - "google.api.expr.test.v1.proto2.GlobalEnum.GAR")); + descriptorTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.GlobalEnum.GAR")); } @Test public void lookupEnumValue_notFoundValue() { Integer enumValue = - compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.GlobalEnum.BAR"); + compatTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.GlobalEnum.BAR"); assertThat(enumValue).isNull(); assertThat(enumValue) .isEqualTo( - descriptorTypeProvider.lookupEnumValue( - "google.api.expr.test.v1.proto2.GlobalEnum.BAR")); + descriptorTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.GlobalEnum.BAR")); } @Test public void lookupEnumValue_notFoundEnumType() { Integer enumValue = - compatTypeProvider.lookupEnumValue("google.api.expr.test.v1.proto2.InvalidEnum.TEST"); + compatTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.InvalidEnum.TEST"); assertThat(enumValue).isNull(); assertThat(enumValue) .isEqualTo( - descriptorTypeProvider.lookupEnumValue( - "google.api.expr.test.v1.proto2.InvalidEnum.TEST")); + descriptorTypeProvider.lookupEnumValue("cel.expr.conformance.proto2.InvalidEnum.TEST")); } @Test diff --git a/checker/src/test/java/dev/cel/checker/TypesTest.java b/checker/src/test/java/dev/cel/checker/TypesTest.java index 60be88bb8..960ebec3f 100644 --- a/checker/src/test/java/dev/cel/checker/TypesTest.java +++ b/checker/src/test/java/dev/cel/checker/TypesTest.java @@ -19,8 +19,8 @@ import dev.cel.expr.Type; import dev.cel.expr.Type.PrimitiveType; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.SimpleType; import java.util.HashMap; import java.util.Map; @@ -34,8 +34,8 @@ public class TypesTest { @Test public void isAssignable_usingProtoTypes() { Map subs = new HashMap<>(); - Type typeParamA = CelTypes.createTypeParam("A"); - Type stringType = CelTypes.create(PrimitiveType.STRING); + Type typeParamA = CelProtoTypes.createTypeParam("A"); + Type stringType = CelProtoTypes.create(PrimitiveType.STRING); Map result = Types.isAssignable(subs, typeParamA, stringType); 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/aggregateMessage.baseline b/checker/src/test/resources/aggregateMessage.baseline index 506b5deb6..7bace8021 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 -}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes +}~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.proto3.TestAllTypes diff --git a/checker/src/test/resources/anyMessage.baseline b/checker/src/test/resources/anyMessage.baseline index 83b50bac3..9c94a0b24 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/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 +Source: x == google.protobuf.Any{type_url:'types.googleapis.com/cel.expr.conformance.proto3.TestAllTypes'} && x.single_nested_message.bb == 43 || x == cel.expr.conformance.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/google.api.expr.test.v1.proto3.TestAllTypes"~string + type_url:"types.googleapis.com/cel.expr.conformance.proto3.TestAllTypes"~string }~any^google.protobuf.Any )~bool^equals, _==_( @@ -22,7 +22,7 @@ _||_( )~bool^logical_and, _==_( x~any^x, - google.api.expr.test.v1.proto3.TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes + cel.expr.conformance.proto3.TestAllTypes{}~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.proto3.TestAllTypes )~bool^equals )~bool^logical_or, _||_( diff --git a/checker/src/test/resources/dynOperators.baseline b/checker/src/test/resources/dynOperators.baseline index ae4ea2c41..ceb4ce9e6 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _==_( _+_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_value~dyn, + x~cel.expr.conformance.proto3.TestAllTypes^x.single_value~dyn, _/_( 1~int, - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_struct~map(string, dyn).y~dyn + x~cel.expr.conformance.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 8730c3c35..470289997 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _+_( _[_]( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_value~dyn, + x~cel.expr.conformance.proto3.TestAllTypes^x.single_value~dyn, 23~int )~dyn^index_list|index_map, _[_]( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_struct~map(string, dyn), + x~cel.expr.conformance.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 b861e12d7..be343985a 100644 --- a/checker/src/test/resources/enumValues.baseline +++ b/checker/src/test/resources/enumValues.baseline @@ -1,6 +1,6 @@ Source: TestAllTypes.NestedEnum.BAR != 99 =====> _!=_( - google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR~int^google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum.BAR, + cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR~int^cel.expr.conformance.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 0f7fdbe4e..ad105a5bd 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _&&_( _&&_( _&&_( _==_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), 1~int )~bool^equals, _!=_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int32_wrapper~wrapper(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_int32_wrapper~wrapper(int), 2~int )~bool^not_equals )~bool^logical_and, _!=_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_double_wrapper~wrapper(double), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_double_wrapper~wrapper(double), 2.0~double )~bool^not_equals )~bool^logical_and, _&&_( _&&_( _==_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_float_wrapper~wrapper(double), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_float_wrapper~wrapper(double), 1.0~double )~bool^equals, _==_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_uint32_wrapper~wrapper(uint), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_uint32_wrapper~wrapper(uint), 1u~uint )~bool^equals )~bool^logical_and, _!=_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_uint64_wrapper~wrapper(uint), + x~cel.expr.conformance.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 b2f7ac7dc..9a16481e6 100644 --- a/checker/src/test/resources/globalEnumValues.baseline +++ b/checker/src/test/resources/globalEnumValues.baseline @@ -1,6 +1,6 @@ Source: GlobalEnum.GAZ == 2 =====> _==_( - google.api.expr.test.v1.proto3.GlobalEnum.GAZ~int^google.api.expr.test.v1.proto3.GlobalEnum.GAZ, + cel.expr.conformance.proto3.GlobalEnum.GAZ~int^cel.expr.conformance.proto3.GlobalEnum.GAZ, 2~int )~bool^equals diff --git a/checker/src/test/resources/jsonStructTypeError.baseline b/checker/src/test/resources/jsonStructTypeError.baseline index 83d6bd717..9923ddcda 100644 --- a/checker/src/test/resources/jsonStructTypeError.baseline +++ b/checker/src/test/resources/jsonStructTypeError.baseline @@ -1,8 +1,8 @@ -ource: x["iss"] != TestAllTypes{single_int32: 1} +Source: x["iss"] != TestAllTypes{single_int32: 1} declare x { value google.protobuf.Struct } =====> -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)) +ERROR: test_location:1:10: found no matching overload for '_!=_' applied to '(google.protobuf.Value, cel.expr.conformance.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 469e5b0e6..47f3ccc95 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(google.api.expr.test.v1.proto3.TestAllTypes) + value list(cel.expr.conformance.proto3.TestAllTypes) } declare y { value list(int) } =====> -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)) +ERROR: test_location:1:3: found no matching overload for '_+_' applied to '(list(cel.expr.conformance.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 898590535..c0fca99bf 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(google.api.expr.test.v1.proto3.TestAllTypes) + value list(cel.expr.conformance.proto3.TestAllTypes) } =====> -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)) +ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(list(cel.expr.conformance.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 dba29ba4c..5ca16ba91 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(google.api.expr.test.v1.proto3.TestAllTypes) + value list(cel.expr.conformance.proto3.TestAllTypes) } =====> _==_( _[_]( _+_( - 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, + x~list(cel.expr.conformance.proto3.TestAllTypes)^x, + x~list(cel.expr.conformance.proto3.TestAllTypes)^x + )~list(cel.expr.conformance.proto3.TestAllTypes)^add_list, 1~int - )~google.api.expr.test.v1.proto3.TestAllTypes^index_list.single_int32~int, + )~cel.expr.conformance.proto3.TestAllTypes^index_list.single_int32~int, size( - x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x + x~list(cel.expr.conformance.proto3.TestAllTypes)^x )~int^size_list )~bool^equals Source: x.size() == size(x) declare x { - value list(google.api.expr.test.v1.proto3.TestAllTypes) + value list(cel.expr.conformance.proto3.TestAllTypes) } =====> _==_( - x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x.size()~int^list_size, + x~list(cel.expr.conformance.proto3.TestAllTypes)^x.size()~int^list_size, size( - x~list(google.api.expr.test.v1.proto3.TestAllTypes)^x + x~list(cel.expr.conformance.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 4fd1fe5d5..e04335f98 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _==_( _[_]( - 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 + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.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 a7dc95415..d8ec99820 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _==_( size( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.map_int64_nested_type~map(int, google.api.expr.test.v1.proto3.NestedTestAllTypes) + x~cel.expr.conformance.proto3.TestAllTypes^x.map_int64_nested_type~map(int, cel.expr.conformance.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 4fabfed85..2f7964bc0 100644 --- a/checker/src/test/resources/mapExpr.baseline +++ b/checker/src/test/resources/mapExpr.baseline @@ -1,22 +1,22 @@ Source: x.repeated_int64.map(x, double(x)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> __comprehension__( // Variable x, // Target - x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator - __result__, + @result, // Init []~list(double), // LoopCondition true~bool, // LoopStep _+_( - __result__~list(double)^__result__, + @result~list(double)^@result, [ double( x~int^x @@ -24,20 +24,20 @@ __comprehension__( ]~list(double) )~list(double)^add_list, // Result - __result__~list(double)^__result__)~list(double) + @result~list(double)^@result)~list(double) Source: [].map(x, [].map(y, x in y && y in x)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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))) - | [].map(x, [].map(y, x in y && y in x)) - | ................................^ + | [].map(x, [].map(y, x in y && y in x)) + | ................................^ Source: [{}.map(c,c,c)]+[{}.map(c,c,c)] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _+_( @@ -48,7 +48,7 @@ _+_( // Target {}~map(bool, dyn), // Accumulator - __result__, + @result, // Init []~list(bool), // LoopCondition @@ -57,15 +57,15 @@ _+_( _?_:_( c~bool^c, _+_( - __result__~list(bool)^__result__, + @result~list(bool)^@result, [ c~bool^c ]~list(bool) )~list(bool)^add_list, - __result__~list(bool)^__result__ + @result~list(bool)^@result )~list(bool)^conditional, // Result - __result__~list(bool)^__result__)~list(bool) + @result~list(bool)^@result)~list(bool) ]~list(list(bool)), [ __comprehension__( @@ -74,7 +74,7 @@ _+_( // Target {}~map(bool, dyn), // Accumulator - __result__, + @result, // Init []~list(bool), // LoopCondition @@ -83,14 +83,14 @@ _+_( _?_:_( c~bool^c, _+_( - __result__~list(bool)^__result__, + @result~list(bool)^@result, [ c~bool^c ]~list(bool) )~list(bool)^add_list, - __result__~list(bool)^__result__ + @result~list(bool)^@result )~list(bool)^conditional, // Result - __result__~list(bool)^__result__)~list(bool) + @result~list(bool)^@result)~list(bool) ]~list(list(bool)) -)~list(list(bool))^add_list +)~list(list(bool))^add_list \ No newline at end of file diff --git a/checker/src/test/resources/mapFilterExpr.baseline b/checker/src/test/resources/mapFilterExpr.baseline index 7e7c0175a..1a66e493c 100644 --- a/checker/src/test/resources/mapFilterExpr.baseline +++ b/checker/src/test/resources/mapFilterExpr.baseline @@ -1,15 +1,15 @@ Source: x.repeated_int64.map(x, x > 0, double(x)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> __comprehension__( // Variable x, // Target - x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator - __result__, + @result, // Init []~list(double), // LoopCondition @@ -21,21 +21,21 @@ __comprehension__( 0~int )~bool^greater_int64, _+_( - __result__~list(double)^__result__, + @result~list(double)^@result, [ double( x~int^x )~double^int64_to_double ]~list(double) )~list(double)^add_list, - __result__~list(double)^__result__ + @result~list(double)^@result )~list(double)^conditional, // Result - __result__~list(double)^__result__)~list(double) + @result~list(double)^@result)~list(double) Source: lists.filter(x, x > 1.5) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare lists { value dyn @@ -47,7 +47,7 @@ __comprehension__( // Target lists~dyn^lists, // Accumulator - __result__, + @result, // Init []~list(dyn), // LoopCondition @@ -59,19 +59,19 @@ __comprehension__( 1.5~double )~bool^greater_double|greater_int64_double|greater_uint64_double, _+_( - __result__~list(dyn)^__result__, + @result~list(dyn)^@result, [ x~dyn^x ]~list(dyn) )~list(dyn)^add_list, - __result__~list(dyn)^__result__ + @result~list(dyn)^@result )~list(dyn)^conditional, // Result - __result__~list(dyn)^__result__)~list(dyn) + @result~list(dyn)^@result)~list(dyn) Source: args.user["myextension"].customAttributes.filter(x, x.name == "hobbies") declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare lists { value dyn @@ -89,7 +89,7 @@ __comprehension__( "myextension"~string )~dyn^index_map.customAttributes~dyn, // Accumulator - __result__, + @result, // Init []~list(dyn), // LoopCondition @@ -101,12 +101,12 @@ __comprehension__( "hobbies"~string )~bool^equals, _+_( - __result__~list(dyn)^__result__, + @result~list(dyn)^@result, [ x~dyn^x ]~list(dyn) )~list(dyn)^add_list, - __result__~list(dyn)^__result__ + @result~list(dyn)^@result )~list(dyn)^conditional, // Result - __result__~list(dyn)^__result__)~list(dyn) + @result~list(dyn)^@result)~list(dyn) \ No newline at end of file diff --git a/checker/src/test/resources/mapIndexTypeError.baseline b/checker/src/test/resources/mapIndexTypeError.baseline index ad31488db..02fee54dd 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, google.api.expr.test.v1.proto3.TestAllTypes) + value map(string, cel.expr.conformance.proto3.TestAllTypes) } =====> -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)) +ERROR: test_location:1:2: found no matching overload for '_[_]' applied to '(map(string, cel.expr.conformance.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 454d7f024..cf040f056 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, google.api.expr.test.v1.proto3.TestAllTypes) + value map(string, cel.expr.conformance.proto3.TestAllTypes) } =====> _==_( _[_]( - x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x, + x~map(string, cel.expr.conformance.proto3.TestAllTypes)^x, "a"~string - )~google.api.expr.test.v1.proto3.TestAllTypes^index_map.single_int32~int, + )~cel.expr.conformance.proto3.TestAllTypes^index_map.single_int32~int, 23~int )~bool^equals Source: x.size() == size(x) declare x { - value map(string, google.api.expr.test.v1.proto3.TestAllTypes) + value map(string, cel.expr.conformance.proto3.TestAllTypes) } =====> _==_( - x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x.size()~int^map_size, + x~map(string, cel.expr.conformance.proto3.TestAllTypes)^x.size()~int^map_size, size( - x~map(string, google.api.expr.test.v1.proto3.TestAllTypes)^x + x~map(string, cel.expr.conformance.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 8a219faaf..2247ce751 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _&&_( _&&_( _&&_( _==_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage.bb~int, + x~cel.expr.conformance.proto3.TestAllTypes^x.single_nested_message~cel.expr.conformance.proto3.TestAllTypes.NestedMessage.bb~int, 43~int )~bool^equals, - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~test-only~~bool + x~cel.expr.conformance.proto3.TestAllTypes^x.single_nested_message~test-only~~bool )~bool^logical_and, - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int32~test-only~~bool + x~cel.expr.conformance.proto3.TestAllTypes^x.single_int32~test-only~~bool )~bool^logical_and, _&&_( - 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 + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int32~test-only~~bool, + x~cel.expr.conformance.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 8c1808f1d..2bf3ad7f7 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> ERROR: test_location:1:24: undefined field 'undefined' diff --git a/checker/src/test/resources/namespacedFunctions.baseline b/checker/src/test/resources/namespacedFunctions.baseline index 449ea5110..b6ace0e3e 100644 --- a/checker/src/test/resources/namespacedFunctions.baseline +++ b/checker/src/test/resources/namespacedFunctions.baseline @@ -84,14 +84,14 @@ __comprehension__( )~int^ns_func_overload ]~list(int), // Accumulator - __result__, + @result, // Init []~list(int), // LoopCondition true~bool, // LoopStep _+_( - __result__~list(int)^__result__, + @result~list(int)^@result, [ _*_( x~int^x, @@ -100,7 +100,7 @@ __comprehension__( ]~list(int) )~list(int)^add_list, // Result - __result__~list(int)^__result__)~list(int) + @result~list(int)^@result)~list(int) Source: [1, 2].map(x, x * ns.func('test')) declare ns.func { @@ -119,14 +119,14 @@ __comprehension__( 2~int ]~list(int), // Accumulator - __result__, + @result, // Init []~list(int), // LoopCondition true~bool, // LoopStep _+_( - __result__~list(int)^__result__, + @result~list(int)^@result, [ _*_( x~int^x, @@ -137,7 +137,7 @@ __comprehension__( ]~list(int) )~list(int)^add_list, // Result - __result__~list(int)^__result__)~list(int) + @result~list(int)^@result)~list(int) Source: func('hello') declare ns.func { @@ -165,4 +165,4 @@ ns.func( ns.func( "test"~string )~int^ns_func_overload -)~int^ns_member_overload +)~int^ns_member_overload \ No newline at end of file diff --git a/checker/src/test/resources/namespacedVariables.baseline b/checker/src/test/resources/namespacedVariables.baseline index ecb3cfc30..b7594c820 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 google.api.expr.test.v1.proto3.msgVar { - value google.api.expr.test.v1.proto3.TestAllTypes +declare cel.expr.conformance.proto3.msgVar { + value cel.expr.conformance.proto3.TestAllTypes } =====> -google.api.expr.test.v1.proto3.msgVar~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.msgVar.single_int32~int +cel.expr.conformance.proto3.msgVar~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.proto3.msgVar.single_int32~int diff --git a/checker/src/test/resources/nestedEnums.baseline b/checker/src/test/resources/nestedEnums.baseline index 98b5477c7..211fbf4c0 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _==_( - 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 + x~cel.expr.conformance.proto3.TestAllTypes^x.single_nested_enum~int, + cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR~int^cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR )~bool^equals Source: single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare single_nested_enum { value int @@ -18,12 +18,12 @@ declare single_nested_enum { =====> _==_( 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 + cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR~int^cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR )~bool^equals Source: TestAllTypes{single_nested_enum : TestAllTypes.NestedEnum.BAR}.single_nested_enum == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare single_nested_enum { value int @@ -31,7 +31,7 @@ declare single_nested_enum { =====> _==_( TestAllTypes{ - 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, + single_nested_enum:cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR~int^cel.expr.conformance.proto3.TestAllTypes.NestedEnum.BAR + }~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.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 d6920cede..6b5c13a68 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _!=_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_nested_message~google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage, + x~cel.expr.conformance.proto3.TestAllTypes^x.single_nested_message~cel.expr.conformance.proto3.TestAllTypes.NestedMessage, null~null )~bool^not_equals Source: null == TestAllTypes{} || TestAllTypes{} == null declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _||_( _==_( null~null, - TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes + TestAllTypes{}~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.proto3.TestAllTypes )~bool^equals, _==_( - TestAllTypes{}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes, + TestAllTypes{}~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.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 b6e4a7dc7..202497f03 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 f2e0165b0..d8e323193 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _==_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~cel.expr.conformance.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 72123b2ee..f567eb9d5 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _?_:_( false~bool, - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_timestamp~google.protobuf.Timestamp, + x~cel.expr.conformance.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 c78f5cc5a..a86fb1fc7 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 -}~google.api.expr.test.v1.proto3.TestAllTypes^google.api.expr.test.v1.proto3.TestAllTypes +}~cel.expr.conformance.proto3.TestAllTypes^cel.expr.conformance.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 6d5351988..47546cc8b 100644 --- a/checker/src/test/resources/proto2PrimitiveField.baseline +++ b/checker/src/test/resources/proto2PrimitiveField.baseline @@ -1,6 +1,6 @@ Source: x.single_fixed32 != 0u && x.single_fixed64 > 1u && x.single_int32 != null declare x { - value google.api.expr.test.v1.proto2.TestAllTypes + value cel.expr.conformance.proto2.TestAllTypes } =====> ERROR: test_location:1:67: found no matching overload for '_!=_' applied to '(int, null)' (candidates: (%A1, %A1)) @@ -9,10 +9,10 @@ ERROR: test_location:1:67: found no matching overload for '_!=_' applied to '(in Source: x.nestedgroup.single_name == '' declare x { - value google.api.expr.test.v1.proto2.TestAllTypes + value cel.expr.conformance.proto2.TestAllTypes } =====> _==_( - x~google.api.expr.test.v1.proto2.TestAllTypes^x.nestedgroup~google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup.single_name~string, + x~cel.expr.conformance.proto2.TestAllTypes^x.nestedgroup~cel.expr.conformance.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 b2d651c8c..3f204a6f5 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _&&_( @@ -9,58 +9,58 @@ _&&_( // Variable e, // Target - x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator - __result__, + @result, // Init true~bool, // LoopCondition @not_strictly_false( - __result__~bool^__result__ + @result~bool^@result )~bool^not_strictly_false, // LoopStep _&&_( - __result__~bool^__result__, + @result~bool^@result, _>_( e~int^e, 0~int )~bool^greater_int64 )~bool^logical_and, // Result - __result__~bool^__result__)~bool, + @result~bool^@result)~bool, __comprehension__( // Variable e, // Target - x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator - __result__, + @result, // Init false~bool, // LoopCondition @not_strictly_false( !_( - __result__~bool^__result__ + @result~bool^@result )~bool^logical_not )~bool^not_strictly_false, // LoopStep _||_( - __result__~bool^__result__, + @result~bool^@result, _<_( e~int^e, 0~int )~bool^less_int64 )~bool^logical_or, // Result - __result__~bool^__result__)~bool + @result~bool^@result)~bool )~bool^logical_and, __comprehension__( // Variable e, // Target - x~google.api.expr.test.v1.proto3.TestAllTypes^x.repeated_int64~list(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int), // Accumulator - __result__, + @result, // Init 0~int, // LoopCondition @@ -72,14 +72,14 @@ _&&_( 0~int )~bool^equals, _+_( - __result__~int^__result__, + @result~int^@result, 1~int )~int^add_int64, - __result__~int^__result__ + @result~int^@result )~int^conditional, // Result _==_( - __result__~int^__result__, + @result~int^@result, 1~int )~bool^equals)~bool -)~bool^logical_and +)~bool^logical_and \ No newline at end of file diff --git a/checker/src/test/resources/quantifiersErrors.baseline b/checker/src/test/resources/quantifiersErrors.baseline index 2f6d1eac6..17c1736c5 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> -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) +ERROR: test_location:1:1: expression of type 'cel.expr.conformance.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 7bd4487e5..7680854d4 100644 --- a/checker/src/test/resources/referenceTypeAbsolute.baseline +++ b/checker/src/test/resources/referenceTypeAbsolute.baseline @@ -1,3 +1,3 @@ -Source: .google.api.expr.test.v1.proto3.TestAllTypes +Source: .cel.expr.conformance.proto3.TestAllTypes =====> -google.api.expr.test.v1.proto3.TestAllTypes~type(google.api.expr.test.v1.proto3.TestAllTypes)^google.api.expr.test.v1.proto3.TestAllTypes +cel.expr.conformance.proto3.TestAllTypes~type(cel.expr.conformance.proto3.TestAllTypes)^cel.expr.conformance.proto3.TestAllTypes diff --git a/checker/src/test/resources/referenceTypeRelative.baseline b/checker/src/test/resources/referenceTypeRelative.baseline index abe4260d5..e0c681d61 100644 --- a/checker/src/test/resources/referenceTypeRelative.baseline +++ b/checker/src/test/resources/referenceTypeRelative.baseline @@ -1,3 +1,3 @@ Source: proto3.TestAllTypes =====> -google.api.expr.test.v1.proto3.TestAllTypes~type(google.api.expr.test.v1.proto3.TestAllTypes)^google.api.expr.test.v1.proto3.TestAllTypes +cel.expr.conformance.proto3.TestAllTypes~type(cel.expr.conformance.proto3.TestAllTypes)^cel.expr.conformance.proto3.TestAllTypes diff --git a/checker/src/test/resources/referenceValue.baseline b/checker/src/test/resources/referenceValue.baseline index a6ded5464..165b0bc6b 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> -container.x~google.api.expr.test.v1.proto3.TestAllTypes^container.x +container.x~cel.expr.conformance.proto3.TestAllTypes^container.x diff --git a/checker/src/test/resources/standardEnvDump.baseline b/checker/src/test/resources/standardEnvDump.baseline index df1c66553..60d19f66d 100644 --- a/checker/src/test/resources/standardEnvDump.baseline +++ b/checker/src/test/resources/standardEnvDump.baseline @@ -218,11 +218,11 @@ declare getSeconds { } declare int { value type(int) + function int64_to_int64 (int) -> int function uint64_to_int64 (uint) -> 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)) diff --git a/checker/src/test/resources/types.baseline b/checker/src/test/resources/types.baseline index 61f3f4423..939e0ed97 100644 --- a/checker/src/test/resources/types.baseline +++ b/checker/src/test/resources/types.baseline @@ -27,14 +27,14 @@ __comprehension__( // Target {}~map(dyn, dyn), // Accumulator - __result__, + @result, // Init []~list(list(dyn)), // LoopCondition true~bool, // LoopStep _+_( - __result__~list(list(dyn))^__result__, + @result~list(list(dyn))^@result, [ [ c~dyn^c, @@ -45,4 +45,4 @@ __comprehension__( ]~list(list(dyn)) )~list(list(dyn))^add_list, // Result - __result__~list(list(dyn))^__result__)~list(list(dyn)) + @result~list(list(dyn))^@result)~list(list(dyn)) \ No newline at end of file diff --git a/checker/src/test/resources/userFunctionAddsOverload.baseline b/checker/src/test/resources/userFunctionAddsOverload.baseline index 3a8cb44ad..515afa9eb 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare size { - function size_message (google.api.expr.test.v1.proto3.TestAllTypes) -> int + function size_message (cel.expr.conformance.proto3.TestAllTypes) -> int } =====> _>_( size( - x~google.api.expr.test.v1.proto3.TestAllTypes^x + x~cel.expr.conformance.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 2180c4a5f..3b3b82375 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> _!=_( _+_( - x~google.api.expr.test.v1.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), + x~cel.expr.conformance.proto3.TestAllTypes^x.single_int64_wrapper~wrapper(int), 1~int )~int^add_int64, 23~int 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/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index 9e4fa12fd..31fd401c5 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -60,7 +60,6 @@ java_library( "//common/types", "//common/types:cel_types", "//common/types:type_providers", - "@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", @@ -79,7 +78,7 @@ java_library( "//:auto_value", "//common/annotations", "//common/internal:safe_string_formatter", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", @@ -119,7 +118,7 @@ java_library( deps = [ "//common", "//common/ast:expr_converter", - "//common/types:cel_types", + "//common/types:cel_proto_types", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", diff --git a/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java b/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java index 59023adfd..6b3b6a74f 100644 --- a/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java +++ b/common/src/main/java/dev/cel/common/CelAbstractSyntaxTree.java @@ -14,7 +14,6 @@ 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; @@ -24,7 +23,6 @@ import dev.cel.common.ast.CelExpr; import dev.cel.common.ast.CelReference; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import dev.cel.common.types.SimpleType; import java.util.Map; import java.util.NoSuchElementException; @@ -94,14 +92,6 @@ public CelType getResultType() { return isChecked() ? getType(getExpr().id()).get() : SimpleType.DYN; } - /** - * For a type checked abstract syntax tree the resulting type is returned in proto format - * described in checked.proto. Otherwise, the dynamic type is returned. - */ - public Type getProtoResultType() { - return CelTypes.celTypeToType(getResultType()); - } - /** * Returns the {@link CelSource} that was used during construction of the abstract syntax tree. */ diff --git a/common/src/main/java/dev/cel/common/CelException.java b/common/src/main/java/dev/cel/common/CelException.java index 55c8623a4..9d80a9ba1 100644 --- a/common/src/main/java/dev/cel/common/CelException.java +++ b/common/src/main/java/dev/cel/common/CelException.java @@ -27,6 +27,11 @@ public CelException(String message, Throwable cause) { super(message, cause); } + public CelException(String message, CelErrorCode errorCode) { + super(message); + this.errorCode = errorCode; + } + public CelException(String message, Throwable cause, CelErrorCode errorCode) { super(message, cause); this.errorCode = errorCode; diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index 2568099fb..3e841471f 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -67,6 +67,8 @@ public enum ProtoUnsetFieldOptions { public abstract boolean retainUnbalancedLogicalExpressions(); + public abstract boolean enableHiddenAccumulatorVar(); + // Type-Checker related options public abstract boolean enableCompileTimeOverloadResolution(); @@ -109,6 +111,14 @@ public enum ProtoUnsetFieldOptions { public abstract ProtoUnsetFieldOptions fromProtoUnsetFieldOption(); + public abstract boolean enableStringConversion(); + + public abstract boolean enableStringConcatenation(); + + public abstract boolean enableListConcatenation(); + + public abstract boolean enableComprehension(); + public abstract Builder toBuilder(); public ImmutableSet toExprFeatures() { @@ -180,6 +190,7 @@ public static Builder newBuilder() { .populateMacroCalls(false) .retainRepeatedUnaryOperators(false) .retainUnbalancedLogicalExpressions(false) + .enableHiddenAccumulatorVar(false) // Type-Checker options .enableCompileTimeOverloadResolution(false) .enableHomogeneousLiterals(false) @@ -200,7 +211,11 @@ public static Builder newBuilder() { .enableCelValue(false) .comprehensionMaxIterations(-1) .unwrapWellKnownTypesOnFunctionDispatch(true) - .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT); + .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT) + .enableStringConversion(true) + .enableStringConcatenation(true) + .enableListConcatenation(true) + .enableComprehension(true); } /** @@ -307,6 +322,16 @@ public abstract static class Builder { */ public abstract Builder retainUnbalancedLogicalExpressions(boolean value); + /** + * Enable the use of a hidden accumulator variable name. + * + *

This is a temporary option to transition to using an internal identifier for the + * accumulator variable used by builtin comprehension macros. When enabled, parses result in a + * semantically equivalent AST, but with a different accumulator variable that can't be directly + * referenced in the source expression. + */ + public abstract Builder enableHiddenAccumulatorVar(boolean value); + // Type-Checker related options /** @@ -417,7 +442,11 @@ public abstract static class Builder { /** * Use {@code UnsignedLong} values to represent unsigned integers within CEL instead of the * nearest Java equivalent of {@code Long}. + * + * @deprecated Do not use. This option is enabled by default in the currently supported feature + * set {@link CelOptions#DEFAULT}. This flag will be removed in the future. */ + @Deprecated public abstract Builder enableUnsignedLongs(boolean value); /** @@ -504,6 +533,31 @@ public abstract static class Builder { */ public abstract Builder fromProtoUnsetFieldOption(ProtoUnsetFieldOptions value); + /** + * Enables string() overloads for the runtime. This option exists to maintain parity with + * cel-cpp interpreter options. + */ + public abstract Builder enableStringConversion(boolean value); + + /** + * Enables string concatenation overload for the runtime. This option exists to maintain parity + * with cel-cpp interpreter options. + */ + public abstract Builder enableStringConcatenation(boolean value); + + /** + * Enables list concatenation overload for the runtime. This option exists to maintain parity + * with cel-cpp interpreter options. + */ + public abstract Builder enableListConcatenation(boolean value); + + /** + * Enables comprehension (macros) for the runtime. Setting false has the same effect with + * assigning 0 for {@link #comprehensionMaxIterations()}. This option exists to maintain parity + * with cel-cpp interpreter options. + */ + public abstract Builder enableComprehension(boolean value); + public abstract CelOptions build(); } } diff --git a/common/src/main/java/dev/cel/common/CelOverloadDecl.java b/common/src/main/java/dev/cel/common/CelOverloadDecl.java index 247f86bc1..1d9c61e9d 100644 --- a/common/src/main/java/dev/cel/common/CelOverloadDecl.java +++ b/common/src/main/java/dev/cel/common/CelOverloadDecl.java @@ -25,8 +25,8 @@ import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; import dev.cel.common.types.CelKind; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import java.util.Arrays; import java.util.List; @@ -230,10 +230,10 @@ public static Overload celOverloadToOverload(CelOverloadDecl overload) { return Overload.newBuilder() .setIsInstanceFunction(overload.isInstanceFunction()) .setOverloadId(overload.overloadId()) - .setResultType(CelTypes.celTypeToType(overload.resultType())) + .setResultType(CelProtoTypes.celTypeToType(overload.resultType())) .addAllParams( overload.parameterTypes().stream() - .map(CelTypes::celTypeToType) + .map(CelProtoTypes::celTypeToType) .collect(toImmutableList())) .addAllTypeParams(overload.typeParameterNames()) .setDoc(overload.doc()) @@ -244,11 +244,11 @@ public static CelOverloadDecl overloadToCelOverload(Overload overload) { return CelOverloadDecl.newBuilder() .setIsInstanceFunction(overload.getIsInstanceFunction()) .setOverloadId(overload.getOverloadId()) - .setResultType(CelTypes.typeToCelType(overload.getResultType())) + .setResultType(CelProtoTypes.typeToCelType(overload.getResultType())) .setDoc(overload.getDoc()) .addParameterTypes( overload.getParamsList().stream() - .map(CelTypes::typeToCelType) + .map(CelProtoTypes::typeToCelType) .collect(toImmutableList())) .build(); } diff --git a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java index f8374e114..7230c80af 100644 --- a/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java +++ b/common/src/main/java/dev/cel/common/CelProtoAbstractSyntaxTree.java @@ -29,7 +29,7 @@ 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 dev.cel.common.types.CelProtoTypes; import java.util.Collection; import java.util.Map.Entry; @@ -66,7 +66,8 @@ private CelProtoAbstractSyntaxTree(CheckedExpr checkedExpr) { Entry::getKey, v -> CelExprConverter.exprReferenceToCelReference(v.getValue()))), checkedExpr.getTypeMapMap().entrySet().stream() - .collect(toImmutableMap(Entry::getKey, v -> CelTypes.typeToCelType(v.getValue())))); + .collect( + toImmutableMap(Entry::getKey, v -> CelProtoTypes.typeToCelType(v.getValue())))); } private CelProtoAbstractSyntaxTree(CelAbstractSyntaxTree ast) { @@ -98,7 +99,8 @@ private CelProtoAbstractSyntaxTree(CelAbstractSyntaxTree ast) { v -> CelExprConverter.celReferenceToExprReference(v.getValue())))); checkedExprBuilder.putAllTypeMap( ast.getTypeMap().entrySet().stream() - .collect(toImmutableMap(Entry::getKey, v -> CelTypes.celTypeToType(v.getValue())))); + .collect( + toImmutableMap(Entry::getKey, v -> CelProtoTypes.celTypeToType(v.getValue())))); } this.checkedExpr = checkedExprBuilder.build(); @@ -182,7 +184,7 @@ public ParsedExpr toParsedExpr() { */ @CheckReturnValue public Type getProtoResultType() { - return CelTypes.celTypeToType(ast.getResultType()); + return CelProtoTypes.celTypeToType(ast.getResultType()); } private static ImmutableList fromCelExtensionsToExprExtensions( 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/common/src/main/java/dev/cel/common/internal/BUILD.bazel b/common/src/main/java/dev/cel/common/internal/BUILD.bazel index 6b83b441a..bb9d67bff 100644 --- a/common/src/main/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/internal/BUILD.bazel @@ -126,7 +126,6 @@ java_library( "//common:proto_json_adapter", "//common:runtime_exception", "//common/annotations", - "@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", 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/ProtoAdapter.java b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java index 29fece49c..28da7e5d0 100644 --- a/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java +++ b/common/src/main/java/dev/cel/common/internal/ProtoAdapter.java @@ -17,7 +17,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableMap.toImmutableMap; -import dev.cel.expr.ExprValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.Ints; @@ -205,9 +204,6 @@ public Object adaptProtoToValue(MessageOrBuilder proto) { @SuppressWarnings({"unchecked", "rawtypes"}) public Optional adaptFieldToValue(FieldDescriptor fieldDescriptor, Object fieldValue) { - if (isUnknown(fieldValue)) { - return Optional.of(fieldValue); - } if (fieldDescriptor.isMapField()) { Descriptor entryDescriptor = fieldDescriptor.getMessageType(); FieldDescriptor keyFieldDescriptor = entryDescriptor.findFieldByNumber(1); @@ -255,9 +251,6 @@ public Optional adaptValueToFieldType( if (isWrapperType(fieldDescriptor) && fieldValue.equals(NullValue.NULL_VALUE)) { return Optional.empty(); } - if (isUnknown(fieldValue)) { - return Optional.of(fieldValue); - } if (fieldDescriptor.isMapField()) { Descriptor entryDescriptor = fieldDescriptor.getMessageType(); FieldDescriptor keyDescriptor = entryDescriptor.findFieldByNumber(1); @@ -590,11 +583,6 @@ private static boolean isWrapperType(FieldDescriptor fieldDescriptor) { return wellKnownProto != null && wellKnownProto.isWrapperType(); } - private static boolean isUnknown(Object object) { - return object instanceof ExprValue - && ((ExprValue) object).getKindCase() == ExprValue.KindCase.UNKNOWN; - } - private static int intCheckedCast(long value) { try { return Ints.checkedCast(value); 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(); 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 4f4029419..752c6df9f 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -71,10 +71,23 @@ java_library( tags = [ ], deps = [ - ":cel_internal_types", ":type_providers", ":types", "//common/annotations", + "@maven//:com_google_guava_guava", + ], +) + +java_library( + name = "cel_proto_types", + srcs = ["CelProtoTypes.java"], + tags = [ + ], + deps = [ + ":cel_internal_types", + ":cel_types", + ":type_providers", + ":types", "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/common/src/main/java/dev/cel/common/types/CelProtoTypes.java b/common/src/main/java/dev/cel/common/types/CelProtoTypes.java new file mode 100644 index 000000000..1c240ca1a --- /dev/null +++ b/common/src/main/java/dev/cel/common/types/CelProtoTypes.java @@ -0,0 +1,281 @@ +// 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.types; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import dev.cel.expr.Type; +import dev.cel.expr.Type.AbstractType; +import dev.cel.expr.Type.PrimitiveType; +import dev.cel.expr.Type.WellKnownType; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Empty; +import com.google.protobuf.NullValue; + +/** + * Utility class for working with {@link Type}. + * + *

This is equivalent to {@link CelTypes}, except this works specifically with canonical CEL expr + * protos. + */ +public final class CelProtoTypes { + + public static final Type ERROR = Type.newBuilder().setError(Empty.getDefaultInstance()).build(); + public static final Type DYN = Type.newBuilder().setDyn(Empty.getDefaultInstance()).build(); + public static final Type NULL_TYPE = Type.newBuilder().setNull(NullValue.NULL_VALUE).build(); + public static final Type BOOL = create(PrimitiveType.BOOL); + public static final Type BYTES = create(PrimitiveType.BYTES); + public static final Type STRING = create(PrimitiveType.STRING); + public static final Type DOUBLE = create(PrimitiveType.DOUBLE); + public static final Type UINT64 = create(PrimitiveType.UINT64); + public static final Type INT64 = create(PrimitiveType.INT64); + public static final Type ANY = create(WellKnownType.ANY); + public static final Type TIMESTAMP = create(WellKnownType.TIMESTAMP); + public static final Type DURATION = create(WellKnownType.DURATION); + + private static final ImmutableMap SIMPLE_CEL_KIND_TO_TYPE = + ImmutableMap.builder() + .put(CelKind.ERROR, ERROR) + .put(CelKind.DYN, DYN) + .put(CelKind.ANY, ANY) + .put(CelKind.BOOL, BOOL) + .put(CelKind.BYTES, BYTES) + .put(CelKind.DOUBLE, DOUBLE) + .put(CelKind.DURATION, DURATION) + .put(CelKind.INT, INT64) + .put(CelKind.NULL_TYPE, NULL_TYPE) + .put(CelKind.STRING, STRING) + .put(CelKind.TIMESTAMP, TIMESTAMP) + .put(CelKind.UINT, UINT64) + .buildOrThrow(); + + private static final ImmutableMap PROTOBUF_TYPE_TO_CEL_TYPE_MAP = + ImmutableMap.builder() + .put(BOOL, SimpleType.BOOL) + .put(BYTES, SimpleType.BYTES) + .put(DOUBLE, SimpleType.DOUBLE) + .put(INT64, SimpleType.INT) + .put(STRING, SimpleType.STRING) + .put(UINT64, SimpleType.UINT) + .put(ANY, SimpleType.ANY) + .put(DURATION, SimpleType.DURATION) + .put(TIMESTAMP, SimpleType.TIMESTAMP) + .put(DYN, SimpleType.DYN) + .put(NULL_TYPE, SimpleType.NULL_TYPE) + .put(ERROR, SimpleType.ERROR) + .buildOrThrow(); + + /** Create a primitive {@code Type}. */ + public static Type create(PrimitiveType type) { + return Type.newBuilder().setPrimitive(type).build(); + } + + /** Create a well-known {@code Type}. */ + public static Type create(WellKnownType type) { + return Type.newBuilder().setWellKnown(type).build(); + } + + /** Create a type {@code Type}. */ + public static Type create(Type target) { + return Type.newBuilder().setType(target).build(); + } + + /** Create a list with {@code elemType}. */ + public static Type createList(Type elemType) { + return Type.newBuilder().setListType(Type.ListType.newBuilder().setElemType(elemType)).build(); + } + + /** Create a map with {@code keyType} and {@code valueType}. */ + public static Type createMap(Type keyType, Type valueType) { + return Type.newBuilder() + .setMapType(Type.MapType.newBuilder().setKeyType(keyType).setValueType(valueType)) + .build(); + } + + /** Create a message {@code Type} for {@code messageName}. */ + public static Type createMessage(String messageName) { + return Type.newBuilder().setMessageType(messageName).build(); + } + + /** Create a message {@code Type} for {@code Descriptor}. */ + public static Type createMessage(Descriptor descriptor) { + return createMessage(descriptor.getFullName()); + } + + /** Create a type param {@code Type}. */ + public static Type createTypeParam(String name) { + return Type.newBuilder().setTypeParam(name).build(); + } + + /** Create a wrapper type for the {@code primitive}. */ + public static Type createWrapper(PrimitiveType primitive) { + return Type.newBuilder().setWrapper(primitive).build(); + } + + /** Create a wrapper type where the input is a {@code Type} of primitive types. */ + public static Type createWrapper(Type type) { + Preconditions.checkArgument(type.getTypeKindCase() == Type.TypeKindCase.PRIMITIVE); + return createWrapper(type.getPrimitive()); + } + + /** + * Create an abstract type indicating that the parameterized type may be contained within the + * object. + */ + public static Type createOptionalType(Type paramType) { + return Type.newBuilder() + .setAbstractType( + AbstractType.newBuilder() + .setName(OptionalType.NAME) + .addParameterTypes(paramType) + .build()) + .build(); + } + + /** Checks if the provided parameter is an optional type */ + public static boolean isOptionalType(Type type) { + return type.hasAbstractType() && type.getAbstractType().getName().equals(OptionalType.NAME); + } + + /** + * Method to adapt a simple {@code Type} into a {@code String} representation. + * + *

This method can also format global functions. See the {@link CelTypes#formatFunction} + * methods for richer control over function formatting. + */ + public static String format(Type type) { + return CelTypes.format(typeToCelType(type), /* typeParamToDyn= */ false); + } + + /** Converts a Protobuf type into CEL native type. */ + public static Type celTypeToType(CelType celType) { + Type type = SIMPLE_CEL_KIND_TO_TYPE.get(celType.kind()); + if (type != null) { + if (celType instanceof NullableType) { + return createWrapper(type); + } + return type; + } + + switch (celType.kind()) { + case UNSPECIFIED: + return Type.getDefaultInstance(); + case LIST: + ListType listType = (ListType) celType; + if (listType.hasElemType()) { + return createList(celTypeToType(listType.elemType())); + } else { + // TODO: Exists for compatibility reason only. Remove after callers have been + // migrated. + return Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build(); + } + case MAP: + MapType mapType = (MapType) celType; + return createMap(celTypeToType(mapType.keyType()), celTypeToType(mapType.valueType())); + case OPAQUE: + if (celType.name().equals("function")) { + Type.FunctionType.Builder functionBuilder = Type.FunctionType.newBuilder(); + if (!celType.parameters().isEmpty()) { + functionBuilder + .setResultType(celTypeToType(celType.parameters().get(0))) + .addAllArgTypes( + celType.parameters().stream() + .skip(1) + .map(CelProtoTypes::celTypeToType) + .collect(toImmutableList())); + } + return Type.newBuilder().setFunction(functionBuilder).build(); + } else { + return Type.newBuilder() + .setAbstractType( + Type.AbstractType.newBuilder() + .setName(celType.name()) + .addAllParameterTypes( + celType.parameters().stream() + .map(CelProtoTypes::celTypeToType) + .collect(toImmutableList()))) + .build(); + } + case STRUCT: + return createMessage(celType.name()); + case TYPE: + TypeType typeType = (TypeType) celType; + return create(celTypeToType(typeType.type())); + case TYPE_PARAM: + return createTypeParam(celType.name()); + default: + throw new IllegalArgumentException(String.format("Unsupported type: %s", celType)); + } + } + + /** Converts a Protobuf type to CEL native type. */ + public static CelType typeToCelType(Type type) { + CelType celType = PROTOBUF_TYPE_TO_CEL_TYPE_MAP.get(type); + if (celType != null) { + return celType; + } + + switch (type.getTypeKindCase()) { + case TYPEKIND_NOT_SET: + return UnspecifiedType.create(); + case WRAPPER: + return NullableType.create(typeToCelType(create(type.getWrapper()))); + case MESSAGE_TYPE: + return StructTypeReference.create(type.getMessageType()); + case LIST_TYPE: + Type.ListType listType = type.getListType(); + if (listType.hasElemType()) { + return ListType.create(typeToCelType(listType.getElemType())); + } else { + // TODO: Exists for compatibility reason only. Remove after callers have been + // migrated. + return ListType.create(); + } + case MAP_TYPE: + Type.MapType mapType = type.getMapType(); + return MapType.create( + typeToCelType(mapType.getKeyType()), typeToCelType(mapType.getValueType())); + case TYPE_PARAM: + return TypeParamType.create(type.getTypeParam()); + case ABSTRACT_TYPE: + Type.AbstractType abstractType = type.getAbstractType(); + ImmutableList params = + abstractType.getParameterTypesList().stream() + .map(CelProtoTypes::typeToCelType) + .collect(toImmutableList()); + if (abstractType.getName().equals(OptionalType.NAME)) { + return OptionalType.create(params.get(0)); + } + return OpaqueType.create(abstractType.getName(), params); + case TYPE: + return TypeType.create(typeToCelType(type.getType())); + case FUNCTION: + Type.FunctionType functionType = type.getFunction(); + return CelTypes.createFunctionType( + typeToCelType(functionType.getResultType()), + functionType.getArgTypesList().stream() + .map(CelProtoTypes::typeToCelType) + .collect(toImmutableList())); + default: + // Add more cases as needed. + throw new IllegalArgumentException(String.format("Unsupported type: %s", type)); + } + } + + private CelProtoTypes() {} +} diff --git a/common/src/main/java/dev/cel/common/types/CelTypes.java b/common/src/main/java/dev/cel/common/types/CelTypes.java index 1d1782145..34e0fa5ef 100644 --- a/common/src/main/java/dev/cel/common/types/CelTypes.java +++ b/common/src/main/java/dev/cel/common/types/CelTypes.java @@ -14,25 +14,14 @@ package dev.cel.common.types; -import static com.google.common.collect.ImmutableList.toImmutableList; - -import dev.cel.expr.Type; -import dev.cel.expr.Type.AbstractType; -import dev.cel.expr.Type.PrimitiveType; -import dev.cel.expr.Type.WellKnownType; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -import com.google.protobuf.Descriptors.Descriptor; -import com.google.protobuf.Empty; -import com.google.protobuf.NullValue; import dev.cel.common.annotations.Internal; import java.util.Optional; -/** Utility class for working with {@link Type}. */ +/** Utility class for working with {@code CelType}. */ public final class CelTypes { // Message type names with well-known type equivalents or special handling. @@ -54,40 +43,6 @@ public final class CelTypes { public static final String UINT32_WRAPPER_MESSAGE = "google.protobuf.UInt32Value"; public static final String UINT64_WRAPPER_MESSAGE = "google.protobuf.UInt64Value"; - // Static types. - public static final Type ERROR = Type.newBuilder().setError(Empty.getDefaultInstance()).build(); - public static final Type DYN = Type.newBuilder().setDyn(Empty.getDefaultInstance()).build(); - public static final Type NULL_TYPE = Type.newBuilder().setNull(NullValue.NULL_VALUE).build(); - public static final Type BOOL = create(PrimitiveType.BOOL); - public static final Type BYTES = create(PrimitiveType.BYTES); - public static final Type STRING = create(PrimitiveType.STRING); - public static final Type DOUBLE = create(PrimitiveType.DOUBLE); - public static final Type UINT64 = create(PrimitiveType.UINT64); - public static final Type INT64 = create(PrimitiveType.INT64); - public static final Type ANY = create(WellKnownType.ANY); - public static final Type TIMESTAMP = create(WellKnownType.TIMESTAMP); - public static final Type DURATION = create(WellKnownType.DURATION); - - /** Map of well-known proto messages and their CEL {@code Type} equivalents. */ - static final ImmutableMap WELL_KNOWN_TYPE_MAP = - ImmutableMap.builder() - .put(DOUBLE_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.DOUBLE)) - .put(FLOAT_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.DOUBLE)) - .put(INT64_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.INT64)) - .put(INT32_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.INT64)) - .put(UINT64_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.UINT64)) - .put(UINT32_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.UINT64)) - .put(BOOL_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.BOOL)) - .put(STRING_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.STRING)) - .put(BYTES_WRAPPER_MESSAGE, CelTypes.createWrapper(CelTypes.BYTES)) - .put(TIMESTAMP_MESSAGE, CelTypes.TIMESTAMP) - .put(DURATION_MESSAGE, CelTypes.DURATION) - .put(STRUCT_MESSAGE, CelTypes.createMap(CelTypes.STRING, CelTypes.DYN)) - .put(VALUE_MESSAGE, CelTypes.DYN) - .put(LIST_VALUE_MESSAGE, CelTypes.createList(CelTypes.DYN)) - .put(ANY_MESSAGE, CelTypes.ANY) - .buildOrThrow(); - private static final ImmutableMap WELL_KNOWN_CEL_TYPE_MAP = ImmutableMap.builder() .put(BOOL_WRAPPER_MESSAGE, NullableType.create(SimpleType.BOOL)) @@ -107,91 +62,6 @@ public final class CelTypes { .put(VALUE_MESSAGE, SimpleType.DYN) .buildOrThrow(); - static final ImmutableMap SIMPLE_CEL_KIND_TO_TYPE = - ImmutableMap.builder() - .put(CelKind.ERROR, CelTypes.ERROR) - .put(CelKind.DYN, CelTypes.DYN) - .put(CelKind.ANY, CelTypes.ANY) - .put(CelKind.BOOL, CelTypes.BOOL) - .put(CelKind.BYTES, CelTypes.BYTES) - .put(CelKind.DOUBLE, CelTypes.DOUBLE) - .put(CelKind.DURATION, CelTypes.DURATION) - .put(CelKind.INT, CelTypes.INT64) - .put(CelKind.NULL_TYPE, CelTypes.NULL_TYPE) - .put(CelKind.STRING, CelTypes.STRING) - .put(CelKind.TIMESTAMP, CelTypes.TIMESTAMP) - .put(CelKind.UINT, CelTypes.UINT64) - .buildOrThrow(); - - private static final ImmutableMap PROTOBUF_TYPE_TO_CEL_TYPE_MAP = - ImmutableMap.builder() - .put(CelTypes.BOOL, SimpleType.BOOL) - .put(CelTypes.BYTES, SimpleType.BYTES) - .put(CelTypes.DOUBLE, SimpleType.DOUBLE) - .put(CelTypes.INT64, SimpleType.INT) - .put(CelTypes.STRING, SimpleType.STRING) - .put(CelTypes.UINT64, SimpleType.UINT) - .put(CelTypes.ANY, SimpleType.ANY) - .put(CelTypes.DURATION, SimpleType.DURATION) - .put(CelTypes.TIMESTAMP, SimpleType.TIMESTAMP) - .put(CelTypes.DYN, SimpleType.DYN) - .put(CelTypes.NULL_TYPE, SimpleType.NULL_TYPE) - .put(CelTypes.ERROR, SimpleType.ERROR) - .buildOrThrow(); - - /** Create a primitive {@code Type}. */ - public static Type create(PrimitiveType type) { - return Type.newBuilder().setPrimitive(type).build(); - } - - /** Create a well-known {@code Type}. */ - public static Type create(WellKnownType type) { - return Type.newBuilder().setWellKnown(type).build(); - } - - /** Create a type {@code Type}. */ - public static Type create(Type target) { - return Type.newBuilder().setType(target).build(); - } - - /** Create a list with {@code elemType}. */ - public static Type createList(Type elemType) { - return Type.newBuilder().setListType(Type.ListType.newBuilder().setElemType(elemType)).build(); - } - - /** Create a map with {@code keyType} and {@code valueType}. */ - public static Type createMap(Type keyType, Type valueType) { - return Type.newBuilder() - .setMapType(Type.MapType.newBuilder().setKeyType(keyType).setValueType(valueType)) - .build(); - } - - /** Create a message {@code Type} for {@code messageName}. */ - public static Type createMessage(String messageName) { - return Type.newBuilder().setMessageType(messageName).build(); - } - - /** Create a message {@code Type} for {@code Descriptor}. */ - public static Type createMessage(Descriptor descriptor) { - return createMessage(descriptor.getFullName()); - } - - /** Create a type param {@code Type}. */ - public static Type createTypeParam(String name) { - return Type.newBuilder().setTypeParam(name).build(); - } - - /** Create a wrapper type for the {@code primitive}. */ - public static Type createWrapper(PrimitiveType primitive) { - return Type.newBuilder().setWrapper(primitive).build(); - } - - /** Create a wrapper type where the input is a {@code Type} of primitive types. */ - public static Type createWrapper(Type type) { - Preconditions.checkArgument(type.getTypeKindCase() == Type.TypeKindCase.PRIMITIVE); - return createWrapper(type.getPrimitive()); - } - /** Checks if the fully-qualified protobuf type name is a wrapper type. */ public static boolean isWrapperType(String typeName) { switch (typeName) { @@ -210,26 +80,6 @@ public static boolean isWrapperType(String typeName) { } } - /** - * Create an abstract type indicating that the parameterized type may be contained within the - * object. - */ - @VisibleForTesting - public static Type createOptionalType(Type paramType) { - return Type.newBuilder() - .setAbstractType( - AbstractType.newBuilder() - .setName(OptionalType.NAME) - .addParameterTypes(paramType) - .build()) - .build(); - } - - /** Checks if the provided parameter is an optional type */ - public static boolean isOptionalType(Type type) { - return type.hasAbstractType() && type.getAbstractType().getName().equals(OptionalType.NAME); - } - /** * Create an abstract type with an expected result type (first argument in the parameter) and the * argument types. @@ -244,19 +94,6 @@ public static OpaqueType createFunctionType(CelType resultType, IterableThis method can also format global functions. See the {@link #formatFunction} methods for - * richer control over function formatting. - * - * @deprecated Use {@link #format(CelType)} instead. - */ - @Deprecated - public static String format(Type type) { - return format(typeToCelType(type), /* typeParamToDyn= */ false); - } - /** * Method to adapt a simple {@code Type} into a {@code String} representation. * @@ -267,7 +104,7 @@ public static String format(CelType type) { return format(type, /* typeParamToDyn= */ false); } - private static String format(CelType type, boolean typeParamToDyn) { + static String format(CelType type, boolean typeParamToDyn) { if (type instanceof NullableType) { return String.format( "wrapper(%s)", format(((NullableType) type).targetType(), typeParamToDyn)); @@ -363,130 +200,13 @@ public static String formatFunction( } public static boolean isWellKnownType(String typeName) { - return WELL_KNOWN_TYPE_MAP.containsKey(typeName); + return WELL_KNOWN_CEL_TYPE_MAP.containsKey(typeName); } public static Optional getWellKnownCelType(String typeName) { return Optional.ofNullable(WELL_KNOWN_CEL_TYPE_MAP.getOrDefault(typeName, null)); } - /** Converts a Protobuf type into CEL native type. */ - @Internal - public static Type celTypeToType(CelType celType) { - Type type = SIMPLE_CEL_KIND_TO_TYPE.get(celType.kind()); - if (type != null) { - if (celType instanceof NullableType) { - return CelTypes.createWrapper(type); - } - return type; - } - - switch (celType.kind()) { - case UNSPECIFIED: - return Type.getDefaultInstance(); - case LIST: - ListType listType = (ListType) celType; - if (listType.hasElemType()) { - return CelTypes.createList(celTypeToType(listType.elemType())); - } else { - // TODO: Exists for compatibility reason only. Remove after callers have been - // migrated. - return Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build(); - } - case MAP: - MapType mapType = (MapType) celType; - return CelTypes.createMap( - celTypeToType(mapType.keyType()), celTypeToType(mapType.valueType())); - case OPAQUE: - if (celType.name().equals("function")) { - Type.FunctionType.Builder functionBuilder = Type.FunctionType.newBuilder(); - if (!celType.parameters().isEmpty()) { - functionBuilder.setResultType(CelTypes.celTypeToType(celType.parameters().get(0))); - functionBuilder.addAllArgTypes( - celType.parameters().stream() - .skip(1) - .map(CelTypes::celTypeToType) - .collect(toImmutableList())); - } - return Type.newBuilder().setFunction(functionBuilder).build(); - } else { - return Type.newBuilder() - .setAbstractType( - Type.AbstractType.newBuilder() - .setName(celType.name()) - .addAllParameterTypes( - celType.parameters().stream() - .map(CelTypes::celTypeToType) - .collect(toImmutableList()))) - .build(); - } - case STRUCT: - return CelTypes.createMessage(celType.name()); - case TYPE: - TypeType typeType = (TypeType) celType; - return CelTypes.create(celTypeToType(typeType.type())); - case TYPE_PARAM: - return CelTypes.createTypeParam(celType.name()); - default: - throw new IllegalArgumentException(String.format("Unsupported type: %s", celType)); - } - } - - /** Converts a Protobuf type to CEL native type. */ - @Internal - public static CelType typeToCelType(Type type) { - CelType celType = PROTOBUF_TYPE_TO_CEL_TYPE_MAP.get(type); - if (celType != null) { - return celType; - } - - switch (type.getTypeKindCase()) { - case TYPEKIND_NOT_SET: - return UnspecifiedType.create(); - case WRAPPER: - return NullableType.create(typeToCelType(CelTypes.create(type.getWrapper()))); - case MESSAGE_TYPE: - return StructTypeReference.create(type.getMessageType()); - case LIST_TYPE: - Type.ListType listType = type.getListType(); - if (listType.hasElemType()) { - return ListType.create(typeToCelType(listType.getElemType())); - } else { - // TODO: Exists for compatibility reason only. Remove after callers have been - // migrated. - return ListType.create(); - } - case MAP_TYPE: - Type.MapType mapType = type.getMapType(); - return MapType.create( - typeToCelType(mapType.getKeyType()), typeToCelType(mapType.getValueType())); - case TYPE_PARAM: - return TypeParamType.create(type.getTypeParam()); - case ABSTRACT_TYPE: - Type.AbstractType abstractType = type.getAbstractType(); - ImmutableList params = - abstractType.getParameterTypesList().stream() - .map(CelTypes::typeToCelType) - .collect(toImmutableList()); - if (abstractType.getName().equals(OptionalType.NAME)) { - return OptionalType.create(params.get(0)); - } - return OpaqueType.create(abstractType.getName(), params); - case TYPE: - return TypeType.create(typeToCelType(type.getType())); - case FUNCTION: - Type.FunctionType functionType = type.getFunction(); - return CelTypes.createFunctionType( - CelTypes.typeToCelType(functionType.getResultType()), - functionType.getArgTypesList().stream() - .map(CelTypes::typeToCelType) - .collect(toImmutableList())); - default: - // Add more cases as needed. - throw new IllegalArgumentException(String.format("Unsupported type: %s", type)); - } - } - private static String formatTypeArgs(Iterable types, final boolean typeParamToDyn) { return String.format( "(%s)", diff --git a/common/src/main/resources/testdata/proto3/BUILD.bazel b/common/src/main/resources/testdata/proto3/BUILD.bazel index 865c21d84..a7db554d5 100644 --- a/common/src/main/resources/testdata/proto3/BUILD.bazel +++ b/common/src/main/resources/testdata/proto3/BUILD.bazel @@ -1,3 +1,6 @@ +load("@com_google_protobuf//bazel:java_proto_library.bzl", "java_proto_library") +load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/src/test/java/dev/cel/common/BUILD.bazel b/common/src/test/java/dev/cel/common/BUILD.bazel index bac8affe1..e0440d767 100644 --- a/common/src/test/java/dev/cel/common/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/BUILD.bazel @@ -22,7 +22,7 @@ java_library( "//common/ast", "//common/internal", "//common/types", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:cel_v1alpha1_types", "//compiler", "//compiler:compiler_builder", diff --git a/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelAbstractSyntaxTreeTest.java index 2cdf81380..b04f9f406 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.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.CheckedExpr; import dev.cel.expr.Constant; @@ -29,7 +28,7 @@ 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.CelProtoTypes; import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; @@ -58,9 +57,9 @@ public final class CelAbstractSyntaxTreeTest { private static final CelAbstractSyntaxTree CHECKED_ENUM_AST = CelProtoAbstractSyntaxTree.fromCheckedExpr( CheckedExpr.newBuilder() - .putTypeMap(1L, CelTypes.INT64) - .putTypeMap(2L, CelTypes.INT64) - .putTypeMap(3L, CelTypes.BOOL) + .putTypeMap(1L, CelProtoTypes.INT64) + .putTypeMap(2L, CelProtoTypes.INT64) + .putTypeMap(3L, CelProtoTypes.BOOL) .putReferenceMap( 2L, Reference.newBuilder() @@ -95,7 +94,6 @@ public final class CelAbstractSyntaxTreeTest { public void getResultType_isDynWhenParsedExpr() { CelAbstractSyntaxTree ast = PARSED_AST; - assertThat(ast.getProtoResultType()).isEqualTo(CelTypes.DYN); assertThat(ast.getResultType()).isEqualTo(SimpleType.DYN); } @@ -103,7 +101,6 @@ public void getResultType_isDynWhenParsedExpr() { public void getResultType_isStaticWhenCheckedExpr() { CelAbstractSyntaxTree ast = CHECKED_AST; - assertThat(ast.getProtoResultType()).isEqualTo(CelTypes.BOOL); assertThat(ast.getResultType()).isEqualTo(SimpleType.BOOL); } diff --git a/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java b/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java index 1d6170f56..585828549 100644 --- a/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java +++ b/common/src/test/java/dev/cel/common/CelProtoAbstractSyntaxTreeTest.java @@ -28,7 +28,7 @@ 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 dev.cel.common.types.CelProtoTypes; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; @@ -79,7 +79,7 @@ public class CelProtoAbstractSyntaxTreeTest { private static final CheckedExpr CHECKED_EXPR = CheckedExpr.newBuilder() - .putTypeMap(1L, CelTypes.BOOL) + .putTypeMap(1L, CelProtoTypes.BOOL) .putReferenceMap(1L, Reference.newBuilder().addOverloadId("not_equals").build()) .setSourceInfo(SOURCE_INFO) .setExpr(EXPR) @@ -114,13 +114,13 @@ public void getSourceInfo_yieldsEquivalentMessage() { @Test public void getProtoResultType_isDynWhenParsedExpr() { CelProtoAbstractSyntaxTree ast = CelProtoAbstractSyntaxTree.fromParsedExpr(PARSED_EXPR); - assertThat(ast.getProtoResultType()).isEqualTo(CelTypes.DYN); + assertThat(ast.getProtoResultType()).isEqualTo(CelProtoTypes.DYN); } @Test public void getProtoResultType_isStaticWhenCheckedExpr() { CelProtoAbstractSyntaxTree ast = CelProtoAbstractSyntaxTree.fromCheckedExpr(CHECKED_EXPR); - assertThat(ast.getProtoResultType()).isEqualTo(CelTypes.BOOL); + assertThat(ast.getProtoResultType()).isEqualTo(CelProtoTypes.BOOL); } @Test 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 848920037..429edb3b2 100644 --- a/common/src/test/java/dev/cel/common/ast/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/ast/BUILD.bazel @@ -30,7 +30,7 @@ java_library( "//parser:macro", "//parser:operator", "@cel_spec//proto/cel/expr:expr_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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 fee0ef6fd..8bab0ee5b 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprFormatterTest.java @@ -16,16 +16,17 @@ 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; import dev.cel.common.CelFunctionDecl; +import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; 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.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; import org.junit.Test; @@ -173,7 +174,7 @@ public void list() throws Exception { public void struct() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .addMessageTypes(TestAllTypes.getDescriptor()) .addLibraries(CelOptionalLibrary.INSTANCE) .build(); @@ -223,7 +224,7 @@ public void struct() throws Exception { public void map() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .addMessageTypes(TestAllTypes.getDescriptor()) .addLibraries(CelOptionalLibrary.INSTANCE) .build(); @@ -272,6 +273,7 @@ public void map() throws Exception { public void comprehension() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); CelAbstractSyntaxTree ast = celCompiler.compile("[1, 2, 3].exists(x, x > 0)").getAst(); @@ -291,7 +293,7 @@ public void comprehension() throws Exception { + " }\n" + " }\n" + " }\n" - + " accu_var: __result__\n" + + " accu_var: @result\n" + " accu_init: {\n" + " CONSTANT [10] { value: false }\n" + " }\n" @@ -303,7 +305,7 @@ public void comprehension() throws Exception { + " function: !_\n" + " args: {\n" + " IDENT [11] {\n" - + " name: __result__\n" + + " name: @result\n" + " }\n" + " }\n" + " }\n" @@ -315,7 +317,7 @@ public void comprehension() throws Exception { + " function: _||_\n" + " args: {\n" + " IDENT [14] {\n" - + " name: __result__\n" + + " name: @result\n" + " }\n" + " CALL [8] {\n" + " function: _>_\n" @@ -331,7 +333,7 @@ public void comprehension() throws Exception { + " }\n" + " result: {\n" + " IDENT [16] {\n" - + " name: __result__\n" + + " name: @result\n" + " }\n" + " }\n" + "}"); 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 f27c8a347..9365eb61c 100644 --- a/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelExprVisitorTest.java @@ -17,10 +17,10 @@ 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; +import dev.cel.common.CelOptions; import dev.cel.common.ast.CelExpr.CelCall; import dev.cel.common.ast.CelExpr.CelComprehension; import dev.cel.common.ast.CelExpr.CelIdent; @@ -32,6 +32,7 @@ import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; import java.util.Optional; @@ -245,6 +246,7 @@ public void visitCall() throws Exception { public void visitStruct_fieldkey() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) .setContainer(TestAllTypes.getDescriptor().getFullName()) .build(); @@ -320,6 +322,7 @@ public void visitList() throws Exception { public void visitComprehension() throws Exception { CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.ALL) .build(); CelAbstractSyntaxTree ast = celCompiler.compile("[1, 1].all(x, x == 1)").getAst(); @@ -343,7 +346,7 @@ public void visitComprehension() throws Exception { assertThat(comprehension.loopStep().call().args()).hasSize(2); assertThat(visitedReference.list().get().elements()).isEqualTo(iterRangeElements); assertThat(visitedReference.identifier()) - .hasValue(CelIdent.newBuilder().setName("__result__").build()); + .hasValue(CelIdent.newBuilder().setName("@result").build()); assertThat(visitedReference.arguments()).hasSize(10); } 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 d29f67a50..f394508d2 100644 --- a/common/src/test/java/dev/cel/common/internal/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/internal/BUILD.bazel @@ -31,8 +31,8 @@ java_library( "//common/src/test/resources:service_conflicting_name_java_proto", "//common/src/test/resources:single_file_java_proto", "//common/testing", - "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_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", "@com_google_googleapis//google/type:type_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", 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 518c039e9..877d6a976 100644 --- a/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java +++ b/common/src/test/java/dev/cel/common/internal/CombinedDescriptorPoolTest.java @@ -16,13 +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.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -73,12 +73,12 @@ public void findExtensionDescriptor_success() { Optional fieldDescriptor = combinedDescriptorPool.findExtensionDescriptor( - TestAllTypes.getDescriptor(), "google.api.expr.test.v1.proto2.test_all_types_ext"); + TestAllTypes.getDescriptor(), "cel.expr.conformance.proto2.test_all_types_ext"); assertThat(fieldDescriptor).isPresent(); assertThat(fieldDescriptor.get().isExtension()).isTrue(); assertThat(fieldDescriptor.get().getFullName()) - .isEqualTo("google.api.expr.test.v1.proto2.test_all_types_ext"); + .isEqualTo("cel.expr.conformance.proto2.test_all_types_ext"); } @Test 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 c035db244..4fc36f1b5 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultInstanceMessageFactoryTest.java @@ -18,7 +18,6 @@ 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; @@ -32,6 +31,7 @@ import com.google.testing.junit.testparameterinjector.TestParameterInjector; import dev.cel.common.testdata.ProtoJavaApiVersion1.Proto2JavaVersion1Message; import dev.cel.common.testing.RepeatedTestProvider; +import dev.cel.expr.conformance.proto3.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 16f170746..b26197d04 100644 --- a/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java +++ b/common/src/test/java/dev/cel/common/internal/DefaultMessageFactoryTest.java @@ -17,7 +17,6 @@ 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; @@ -30,6 +29,7 @@ import dev.cel.common.CelDescriptorUtil; import dev.cel.common.CelDescriptors; import dev.cel.common.internal.ProtoMessageFactory.CombinedMessageFactory; +import dev.cel.expr.conformance.proto3.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("google.api.expr.test.v1.proto2.TestAllTypes").get(); + messageFactory.newBuilder("cel.expr.conformance.proto3.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 722d088b0..d35947b9a 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.expr.conformance.proto3.TestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes.NestedEnum; +import dev.cel.expr.conformance.proto3.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 f269a0ce3..d1219c9c1 100644 --- a/common/src/test/java/dev/cel/common/navigation/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/navigation/BUILD.bazel @@ -23,7 +23,7 @@ java_library( "//compiler:compiler_builder", "//parser:macro", "//parser:operator", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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 a8a35dd67..0a4ba42bf 100644 --- a/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java +++ b/common/src/test/java/dev/cel/common/navigation/CelNavigableExprVisitorTest.java @@ -20,7 +20,6 @@ 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; @@ -37,6 +36,7 @@ import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.Operator; import java.util.Optional; @@ -580,7 +580,7 @@ public void messageConstruction_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .build(); CelAbstractSyntaxTree ast = compiler.compile("TestAllTypes{single_int64: 1}").getAst(); CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast); @@ -810,6 +810,7 @@ public void emptyMapConstruction_allNodesReturned() throws Exception { public void comprehension_preOrder_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.EXISTS) .build(); CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); @@ -825,7 +826,7 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); 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 loopConditionIdentExpr = CelExpr.ofIdent(7, "@result"); CelExpr loopConditionCallExpr = CelExpr.ofCall( 8, @@ -838,7 +839,7 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "@result"); CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = CelExpr.ofCall( @@ -846,10 +847,10 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdent(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "@result"); CelExpr comprehension = CelExpr.ofComprehension( - 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); + 13, "i", iterRange, "@result", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(11); assertThat(allNodes) .containsExactly( @@ -871,6 +872,7 @@ public void comprehension_preOrder_allNodesReturned() throws Exception { public void comprehension_postOrder_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.EXISTS) .build(); CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); @@ -886,7 +888,7 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); 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 loopConditionIdentExpr = CelExpr.ofIdent(7, "@result"); CelExpr loopConditionCallExpr = CelExpr.ofCall( 8, @@ -899,7 +901,7 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "@result"); CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = CelExpr.ofCall( @@ -907,10 +909,10 @@ public void comprehension_postOrder_allNodesReturned() throws Exception { Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdent(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "@result"); CelExpr comprehension = CelExpr.ofComprehension( - 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); + 13, "i", iterRange, "@result", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(11); assertThat(allNodes) .containsExactly( @@ -1008,6 +1010,7 @@ public void comprehension_postOrder_maxIdsSet() throws Exception { public void comprehension_allNodes_parentsPopulated() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.EXISTS) .build(); CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); @@ -1018,7 +1021,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); 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 loopConditionIdentExpr = CelExpr.ofIdent(7, "@result"); CelExpr loopConditionCallExpr = CelExpr.ofCall( 8, @@ -1031,7 +1034,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "@result"); CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = CelExpr.ofCall( @@ -1039,10 +1042,10 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdent(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "@result"); CelExpr comprehension = CelExpr.ofComprehension( - 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); + 13, "i", iterRange, "@result", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(11); assertThat(allNodes.get(0).parent()).isEmpty(); // comprehension assertThat(allNodes.get(1).parent().get().expr()).isEqualTo(comprehension); // iter_range @@ -1066,6 +1069,7 @@ public void comprehension_allNodes_parentsPopulated() throws Exception { public void comprehension_filterComprehension_allNodesReturned() throws Exception { CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHiddenAccumulatorVar(true).build()) .setStandardMacros(CelStandardMacro.EXISTS) .build(); CelAbstractSyntaxTree ast = compiler.compile("[true].exists(i, i)").getAst(); @@ -1081,7 +1085,7 @@ public void comprehension_filterComprehension_allNodesReturned() throws Exceptio CelExpr iterRangeConstExpr = CelExpr.ofConstant(2, CelConstant.ofValue(true)); 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 loopConditionIdentExpr = CelExpr.ofIdent(7, "@result"); CelExpr loopConditionCallExpr = CelExpr.ofCall( 8, @@ -1094,7 +1098,7 @@ public void comprehension_filterComprehension_allNodesReturned() throws Exceptio Optional.empty(), Operator.NOT_STRICTLY_FALSE.getFunction(), ImmutableList.of(loopConditionCallExpr)); - CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "__result__"); + CelExpr loopStepResultExpr = CelExpr.ofIdent(10, "@result"); CelExpr loopStepVarExpr = CelExpr.ofIdent(5, "i"); CelExpr loopStep = CelExpr.ofCall( @@ -1102,10 +1106,10 @@ public void comprehension_filterComprehension_allNodesReturned() throws Exceptio Optional.empty(), Operator.LOGICAL_OR.getFunction(), ImmutableList.of(loopStepResultExpr, loopStepVarExpr)); - CelExpr result = CelExpr.ofIdent(12, "__result__"); + CelExpr result = CelExpr.ofIdent(12, "@result"); CelExpr comprehension = CelExpr.ofComprehension( - 13, "i", iterRange, "__result__", accuInit, loopCondition, loopStep, result); + 13, "i", iterRange, "@result", accuInit, loopCondition, loopStep, result); assertThat(allNodes).hasSize(1); assertThat(allNodes.get(0).expr()).isEqualTo(comprehension); } 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 a084efd62..541a77ec0 100644 --- a/common/src/test/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/types/BUILD.bazel @@ -11,12 +11,13 @@ java_library( "//:java_truth", "//common/types", "//common/types:cel_internal_types", + "//common/types:cel_proto_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", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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/CelProtoTypesTest.java b/common/src/test/java/dev/cel/common/types/CelProtoTypesTest.java new file mode 100644 index 000000000..bcddd03fd --- /dev/null +++ b/common/src/test/java/dev/cel/common/types/CelProtoTypesTest.java @@ -0,0 +1,122 @@ +// 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.types; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; + +import dev.cel.expr.Type; +import dev.cel.expr.Type.AbstractType; +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 org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public final class CelProtoTypesTest { + + @Test + public void isOptionalType_true() { + Type optionalType = CelProtoTypes.createOptionalType(CelProtoTypes.INT64); + + assertThat(CelProtoTypes.isOptionalType(optionalType)).isTrue(); + } + + @Test + public void isOptionalType_false() { + Type notOptionalType = + Type.newBuilder() + .setAbstractType(AbstractType.newBuilder().setName("notOptional").build()) + .build(); + + assertThat(CelProtoTypes.isOptionalType(notOptionalType)).isFalse(); + } + + @Test + public void createOptionalType() { + Type optionalType = CelProtoTypes.createOptionalType(CelProtoTypes.INT64); + + assertThat(optionalType.hasAbstractType()).isTrue(); + assertThat(optionalType.getAbstractType().getName()).isEqualTo("optional_type"); + assertThat(optionalType.getAbstractType().getParameterTypesCount()).isEqualTo(1); + assertThat(optionalType.getAbstractType().getParameterTypes(0)).isEqualTo(CelProtoTypes.INT64); + } + + private enum TestCases { + UNSPECIFIED(UnspecifiedType.create(), Type.getDefaultInstance()), + STRING(SimpleType.STRING, CelProtoTypes.STRING), + INT(NullableType.create(SimpleType.INT), CelProtoTypes.createWrapper(CelProtoTypes.INT64)), + UINT(NullableType.create(SimpleType.UINT), CelProtoTypes.createWrapper(CelProtoTypes.UINT64)), + DOUBLE( + NullableType.create(SimpleType.DOUBLE), CelProtoTypes.createWrapper(CelProtoTypes.DOUBLE)), + BOOL(NullableType.create(SimpleType.BOOL), CelProtoTypes.createWrapper(CelProtoTypes.BOOL)), + BYTES(SimpleType.BYTES, CelProtoTypes.BYTES), + ANY(SimpleType.ANY, CelProtoTypes.ANY), + LIST( + ListType.create(), + Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build()), + DYN(ListType.create(SimpleType.DYN), CelProtoTypes.createList(CelProtoTypes.DYN)), + ENUM(EnumType.create("CustomEnum", ImmutableMap.of()), CelProtoTypes.INT64), + STRUCT_TYPE_REF( + StructTypeReference.create("MyCustomStruct"), + CelProtoTypes.createMessage("MyCustomStruct")), + OPAQUE( + OpaqueType.create("vector", SimpleType.UINT), + Type.newBuilder() + .setAbstractType( + AbstractType.newBuilder().setName("vector").addParameterTypes(CelProtoTypes.UINT64)) + .build()), + TYPE_PARAM(TypeParamType.create("T"), CelProtoTypes.createTypeParam("T")), + FUNCTION( + CelTypes.createFunctionType( + SimpleType.INT, ImmutableList.of(SimpleType.STRING, SimpleType.UINT)), + Type.newBuilder() + .setFunction( + Type.FunctionType.newBuilder() + .setResultType(CelProtoTypes.INT64) + .addAllArgTypes(ImmutableList.of(CelProtoTypes.STRING, CelProtoTypes.UINT64))) + .build()), + OPTIONAL( + OptionalType.create(SimpleType.INT), CelProtoTypes.createOptionalType(CelProtoTypes.INT64)), + TYPE( + TypeType.create(MapType.create(SimpleType.STRING, SimpleType.STRING)), + CelProtoTypes.create(CelProtoTypes.createMap(CelProtoTypes.STRING, CelProtoTypes.STRING))); + + private final CelType celType; + private final Type type; + + TestCases(CelType celType, Type type) { + this.celType = celType; + this.type = type; + } + } + + @Test + public void celTypeToType(@TestParameter TestCases testCase) { + assertThat(CelProtoTypes.celTypeToType(testCase.celType)).isEqualTo(testCase.type); + } + + @Test + public void typeToCelType(@TestParameter TestCases testCase) { + if (testCase.celType instanceof EnumType) { + // (b/178627883) Strongly typed enum is not supported yet + return; + } + + assertThat(CelProtoTypes.typeToCelType(testCase.type)).isEqualTo(testCase.celType); + } +} diff --git a/common/src/test/java/dev/cel/common/types/CelTypesTest.java b/common/src/test/java/dev/cel/common/types/CelTypesTest.java index da5c556c5..ae6e0808c 100644 --- a/common/src/test/java/dev/cel/common/types/CelTypesTest.java +++ b/common/src/test/java/dev/cel/common/types/CelTypesTest.java @@ -15,10 +15,8 @@ package dev.cel.common.types; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import dev.cel.expr.Type; -import dev.cel.expr.Type.AbstractType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.testing.junit.testparameterinjector.TestParameter; @@ -29,52 +27,6 @@ @RunWith(TestParameterInjector.class) public final class CelTypesTest { - private enum TestCases { - UNSPECIFIED(UnspecifiedType.create(), Type.getDefaultInstance()), - STRING(SimpleType.STRING, CelTypes.STRING), - INT(NullableType.create(SimpleType.INT), CelTypes.createWrapper(CelTypes.INT64)), - UINT(NullableType.create(SimpleType.UINT), CelTypes.createWrapper(CelTypes.UINT64)), - DOUBLE(NullableType.create(SimpleType.DOUBLE), CelTypes.createWrapper(CelTypes.DOUBLE)), - BOOL(NullableType.create(SimpleType.BOOL), CelTypes.createWrapper(CelTypes.BOOL)), - BYTES(SimpleType.BYTES, CelTypes.BYTES), - ANY(SimpleType.ANY, CelTypes.ANY), - LIST( - ListType.create(), - Type.newBuilder().setListType(Type.ListType.getDefaultInstance()).build()), - DYN(ListType.create(SimpleType.DYN), CelTypes.createList(CelTypes.DYN)), - ENUM(EnumType.create("CustomEnum", ImmutableMap.of()), CelTypes.INT64), - STRUCT_TYPE_REF( - StructTypeReference.create("MyCustomStruct"), CelTypes.createMessage("MyCustomStruct")), - OPAQUE( - OpaqueType.create("vector", SimpleType.UINT), - Type.newBuilder() - .setAbstractType( - AbstractType.newBuilder().setName("vector").addParameterTypes(CelTypes.UINT64)) - .build()), - TYPE_PARAM(TypeParamType.create("T"), CelTypes.createTypeParam("T")), - FUNCTION( - CelTypes.createFunctionType( - SimpleType.INT, ImmutableList.of(SimpleType.STRING, SimpleType.UINT)), - Type.newBuilder() - .setFunction( - Type.FunctionType.newBuilder() - .setResultType(CelTypes.INT64) - .addAllArgTypes(ImmutableList.of(CelTypes.STRING, CelTypes.UINT64))) - .build()), - OPTIONAL(OptionalType.create(SimpleType.INT), CelTypes.createOptionalType(CelTypes.INT64)), - TYPE( - TypeType.create(MapType.create(SimpleType.STRING, SimpleType.STRING)), - CelTypes.create(CelTypes.createMap(CelTypes.STRING, CelTypes.STRING))); - - private final CelType celType; - private final Type type; - - TestCases(CelType celType, Type type) { - this.celType = celType; - this.type = type; - } - } - @Test public void isWellKnownType_true() { assertThat(CelTypes.isWellKnownType(CelTypes.ANY_MESSAGE)).isTrue(); @@ -85,48 +37,6 @@ public void isWellKnownType_false() { assertThat(CelTypes.isWellKnownType("CustomType")).isFalse(); } - @Test - public void createOptionalType() { - Type optionalType = CelTypes.createOptionalType(CelTypes.INT64); - - assertThat(optionalType.hasAbstractType()).isTrue(); - assertThat(optionalType.getAbstractType().getName()).isEqualTo("optional_type"); - assertThat(optionalType.getAbstractType().getParameterTypesCount()).isEqualTo(1); - assertThat(optionalType.getAbstractType().getParameterTypes(0)).isEqualTo(CelTypes.INT64); - } - - @Test - public void isOptionalType_true() { - Type optionalType = CelTypes.createOptionalType(CelTypes.INT64); - - assertThat(CelTypes.isOptionalType(optionalType)).isTrue(); - } - - @Test - public void isOptionalType_false() { - Type notOptionalType = - Type.newBuilder() - .setAbstractType(AbstractType.newBuilder().setName("notOptional").build()) - .build(); - - assertThat(CelTypes.isOptionalType(notOptionalType)).isFalse(); - } - - @Test - public void celTypeToType(@TestParameter TestCases testCase) { - assertThat(CelTypes.celTypeToType(testCase.celType)).isEqualTo(testCase.type); - } - - @Test - public void typeToCelType(@TestParameter TestCases testCase) { - if (testCase.celType instanceof EnumType) { - // (b/178627883) Strongly typed enum is not supported yet - return; - } - - assertThat(CelTypes.typeToCelType(testCase.type)).isEqualTo(testCase.celType); - } - private enum FormatTestCases { UNSPECIFIED(UnspecifiedType.create(), ""), STRING(SimpleType.STRING, "string"), @@ -171,9 +81,9 @@ public void format_withCelType(@TestParameter FormatTestCases testCase) { @Test public void format_withType(@TestParameter FormatTestCases testCase) { - Type type = CelTypes.celTypeToType(testCase.celType); + Type type = CelProtoTypes.celTypeToType(testCase.celType); - assertThat(CelTypes.format(type)).isEqualTo(testCase.formattedString); + assertThat(CelProtoTypes.format(type)).isEqualTo(testCase.formattedString); } @Test 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 a79bb1ffe..d774903e1 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,11 @@ 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.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,13 +33,14 @@ public final class ProtoMessageTypeProviderTest { private final ProtoMessageTypeProvider emptyProvider = new ProtoMessageTypeProvider(); private final ProtoMessageTypeProvider proto3Provider = - new ProtoMessageTypeProvider(ImmutableList.of(TestAllTypes.getDescriptor())); + new ProtoMessageTypeProvider( + ImmutableList.of(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor())); private final ProtoMessageTypeProvider proto2Provider = new ProtoMessageTypeProvider( ImmutableSet.of( + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFile(), TestAllTypes.getDescriptor().getFile(), - TestAllTypesProto.TestAllTypes.getDescriptor().getFile(), TestAllTypesExtensions.getDescriptor())); @Test @@ -57,21 +57,20 @@ public void findType_emptyTypeSet() { public void types_allGlobalAndNestedDeclarations() { assertThat(proto3Provider.types().stream().map(CelType::name).collect(toImmutableList())) .containsAtLeast( - "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"); + "cel.expr.conformance.proto3.GlobalEnum", + "cel.expr.conformance.proto3.TestAllTypes", + "cel.expr.conformance.proto3.TestAllTypes.NestedMessage", + "cel.expr.conformance.proto3.TestAllTypes.NestedEnum", + "cel.expr.conformance.proto3.NestedTestAllTypes"); } @Test public void findType_globalEnumWithAllNamesAndNumbers() { - Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.GlobalEnum"); + Optional celType = proto3Provider.findType("cel.expr.conformance.proto3.GlobalEnum"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); - assertThat(enumType.name()).isEqualTo("google.api.expr.test.v1.proto3.GlobalEnum"); + assertThat(enumType.name()).isEqualTo("cel.expr.conformance.proto3.GlobalEnum"); assertThat(enumType.findNameByNumber(0)).hasValue("GOO"); assertThat(enumType.findNameByNumber(1)).hasValue("GAR"); assertThat(enumType.findNameByNumber(2)).hasValue("GAZ"); @@ -81,11 +80,11 @@ public void findType_globalEnumWithAllNamesAndNumbers() { @Test public void findType_nestedEnumWithAllNamesAndNumbers() { Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); + proto3Provider.findType("cel.expr.conformance.proto3.TestAllTypes.NestedEnum"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(EnumType.class); EnumType enumType = (EnumType) celType.get(); - assertThat(enumType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); + assertThat(enumType.name()).isEqualTo("cel.expr.conformance.proto3.TestAllTypes.NestedEnum"); assertThat(enumType.findNumberByName("FOO")).hasValue(0); assertThat(enumType.findNumberByName("BAR")).hasValue(1); assertThat(enumType.findNumberByName("BAZ")).hasValue(2); @@ -95,11 +94,11 @@ public void findType_nestedEnumWithAllNamesAndNumbers() { @Test public void findType_globalMessageTypeNoExtensions() { Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.NestedTestAllTypes"); + proto3Provider.findType("cel.expr.conformance.proto3.NestedTestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.NestedTestAllTypes"); + assertThat(protoType.name()).isEqualTo("cel.expr.conformance.proto3.NestedTestAllTypes"); assertThat(protoType.findField("payload")).isPresent(); assertThat(protoType.findField("child")).isPresent(); assertThat(protoType.findField("missing")).isEmpty(); @@ -109,100 +108,94 @@ public void findType_globalMessageTypeNoExtensions() { @Test public void findType_globalMessageWithExtensions() { - Optional celType = - proto2Provider.findType("google.api.expr.test.v1.proto2.TestAllTypes"); + Optional celType = proto2Provider.findType("cel.expr.conformance.proto2.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto2.TestAllTypes"); + assertThat(protoType.name()).isEqualTo("cel.expr.conformance.proto2.TestAllTypes"); assertThat(protoType.findField("single_int32")).isPresent(); assertThat(protoType.findField("single_uint64")).isPresent(); assertThat(protoType.findField("oneof_type")).isPresent(); assertThat(protoType.findField("nestedgroup")).isPresent(); assertThat(protoType.findField("nested_enum_ext")).isEmpty(); - 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")) + assertThat(protoType.findExtension("cel.expr.conformance.proto2.nested_ext")).isPresent(); + assertThat(protoType.findExtension("cel.expr.conformance.proto2.int32_ext")).isPresent(); + assertThat(protoType.findExtension("cel.expr.conformance.proto2.test_all_types_ext")) .isPresent(); - assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.nested_enum_ext")) - .isPresent(); - assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.repeated_test_all_types")) + assertThat(protoType.findExtension("cel.expr.conformance.proto2.nested_enum_ext")).isPresent(); + assertThat(protoType.findExtension("cel.expr.conformance.proto2.repeated_test_all_types")) .isPresent(); - assertThat(protoType.findExtension("google.api.expr.test.v1.proto2.TestAllTypes.int32_ext")) + assertThat(protoType.findExtension("cel.expr.conformance.proto2.TestAllTypes.int32_ext")) .isEmpty(); Optional holderType = - proto2Provider.findType("google.api.expr.test.v1.proto2.TestRequired"); + proto2Provider.findType("cel.expr.conformance.proto2.TestRequired"); assertThat(holderType).isPresent(); ProtoMessageType stringHolderType = (ProtoMessageType) holderType.get(); - assertThat(stringHolderType.findExtension("google.api.expr.test.v1.proto2.nested_enum_ext")) + assertThat(stringHolderType.findExtension("cel.expr.conformance.proto2.nested_enum_ext")) .isEmpty(); } @Test public void findType_scopedMessageWithExtensions() { - Optional celType = - proto2Provider.findType("google.api.expr.test.v1.proto2.TestAllTypes"); + Optional celType = proto2Provider.findType("cel.expr.conformance.proto2.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); assertThat( protoType.findExtension( - "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) + "cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); assertThat( protoType.findExtension( - "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext")) + "cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.int64_ext")) .isPresent(); assertThat( protoType.findExtension( - "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types")) + "cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types")) .isPresent(); assertThat( protoType.findExtension( - "google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) + "cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext")) .isPresent(); } @Test public void findType_withRepeatedEnumField() { - Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); + Optional celType = proto3Provider.findType("cel.expr.conformance.proto3.TestAllTypes"); assertThat(celType).isPresent(); assertThat(celType.get()).isInstanceOf(ProtoMessageType.class); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes"); + assertThat(protoType.name()).isEqualTo("cel.expr.conformance.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("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum"); + assertThat(elemType.name()).isEqualTo("cel.expr.conformance.proto3.TestAllTypes.NestedEnum"); assertThat(elemType.kind()).isEqualTo(CelKind.INT); assertThat(elemType).isInstanceOf(EnumType.class); - assertThat(proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes.NestedEnum")) + assertThat(proto3Provider.findType("cel.expr.conformance.proto3.TestAllTypes.NestedEnum")) .hasValue(elemType); } @Test public void findType_withOneofField() { - Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); + Optional celType = proto3Provider.findType("cel.expr.conformance.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); - assertThat(protoType.name()).isEqualTo("google.api.expr.test.v1.proto3.TestAllTypes"); + assertThat(protoType.name()).isEqualTo("cel.expr.conformance.proto3.TestAllTypes"); assertThat(protoType.findField("single_nested_message").map(f -> f.type().name())) - .hasValue("google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage"); + .hasValue("cel.expr.conformance.proto3.TestAllTypes.NestedMessage"); } @Test public void findType_withMapField() { - Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); + Optional celType = proto3Provider.findType("cel.expr.conformance.proto3.TestAllTypes"); ProtoMessageType protoType = (ProtoMessageType) celType.get(); CelType fieldType = protoType.findField("map_int64_nested_type").get().type(); @@ -212,14 +205,13 @@ 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("google.api.expr.test.v1.proto3.NestedTestAllTypes"); + assertThat(valueType.name()).isEqualTo("cel.expr.conformance.proto3.NestedTestAllTypes"); assertThat(valueType.kind()).isEqualTo(CelKind.STRUCT); } @Test public void findType_withWellKnownTypes() { - Optional celType = - proto3Provider.findType("google.api.expr.test.v1.proto3.TestAllTypes"); + Optional celType = proto3Provider.findType("cel.expr.conformance.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())) 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 48e90e120..b7a8dc60e 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -25,7 +25,7 @@ java_library( "//common/values:cel_value_provider", "//common/values:proto_message_value", "//common/values:proto_message_value_provider", - "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_guava_guava_testlib", "@maven//:com_google_protobuf_protobuf_java", 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 0a2fe2ca6..2ce416053 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueProviderTest.java @@ -17,8 +17,6 @@ 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; @@ -34,6 +32,8 @@ import dev.cel.common.internal.DynamicProto; import dev.cel.common.internal.ProtoMessageFactory; import dev.cel.common.values.CelValueProvider.CombinedCelValueProvider; +import dev.cel.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import java.time.Duration; import java.time.Instant; import java.util.Optional; @@ -122,8 +122,7 @@ public void newValue_createProtoMessage_fieldsPopulated() { @Test public void newValue_createProtoMessage_unsignedLongFieldsPopulated() { ProtoMessageValueProvider protoMessageValueProvider = - ProtoMessageValueProvider.newInstance( - DYNAMIC_PROTO, CelOptions.current().enableUnsignedLongs(true).build()); + ProtoMessageValueProvider.newInstance(DYNAMIC_PROTO, CelOptions.current().build()); ProtoMessageValue protoMessageValue = (ProtoMessageValue) @@ -197,13 +196,13 @@ public void newValue_createProtoMessage_extensionFieldsPopulated() { protoMessageValueProvider .newValue( TestAllTypes.getDescriptor().getFullName(), - ImmutableMap.of("google.api.expr.test.v1.proto2.int32_ext", 1)) + ImmutableMap.of("cel.expr.conformance.proto2.int32_ext", 1)) .get(); assertThat(protoMessageValue.isZeroValue()).isFalse(); assertThat( protoMessageValue - .select(StringValue.create("google.api.expr.test.v1.proto2.int32_ext")) + .select(StringValue.create("cel.expr.conformance.proto2.int32_ext")) .value()) .isEqualTo(1); } @@ -239,7 +238,7 @@ public void newValue_invalidField_throws() { .hasMessageThat() .isEqualTo( "field 'bogus' is not declared in message" - + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); + + " 'cel.expr.conformance.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 3a0f6e14e..ab3c52d18 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java @@ -17,10 +17,6 @@ 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; @@ -45,6 +41,10 @@ import dev.cel.common.internal.DefaultMessageFactory; import dev.cel.common.internal.DynamicProto; import dev.cel.common.types.StructTypeReference; +import dev.cel.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypes.NestedEnum; +import dev.cel.expr.conformance.proto2.TestAllTypes.NestedMessage; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import java.time.Duration; import java.time.Instant; import org.junit.Test; @@ -55,7 +55,7 @@ public final class ProtoMessageValueTest { private static final ProtoCelValueConverter PROTO_CEL_VALUE_CONVERTER = ProtoCelValueConverter.newInstance( - CelOptions.current().enableUnsignedLongs(true).build(), + CelOptions.current().build(), DefaultDescriptorPool.INSTANCE, DynamicProto.create(DefaultMessageFactory.INSTANCE)); @@ -129,7 +129,7 @@ public void findField_fieldIsUndeclared_throwsException() { .hasMessageThat() .isEqualTo( "field 'bogus' is not declared in message" - + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); + + " 'cel.expr.conformance.proto2.TestAllTypes'"); } @Test @@ -149,8 +149,7 @@ public void findField_extensionField_success() { ProtoMessageValue protoMessageValue = ProtoMessageValue.create(proto2Message, descriptorPool, protoCelValueConverter); - assertThat( - protoMessageValue.find(StringValue.create("google.api.expr.test.v1.proto2.int32_ext"))) + assertThat(protoMessageValue.find(StringValue.create("cel.expr.conformance.proto2.int32_ext"))) .isPresent(); } @@ -168,12 +167,12 @@ public void findField_extensionField_throwsWhenDescriptorMissing() { IllegalArgumentException.class, () -> protoMessageValue.select( - StringValue.create("google.api.expr.test.v1.proto2.int32_ext"))); + StringValue.create("cel.expr.conformance.proto2.int32_ext"))); assertThat(exception) .hasMessageThat() .isEqualTo( - "field 'google.api.expr.test.v1.proto2.int32_ext' is not declared in message" - + " 'google.api.expr.test.v1.proto2.TestAllTypes'"); + "field 'cel.expr.conformance.proto2.int32_ext' is not declared in message" + + " 'cel.expr.conformance.proto2.TestAllTypes'"); } private enum SelectFieldTestCase { diff --git a/common/src/test/resources/BUILD.bazel b/common/src/test/resources/BUILD.bazel index f53608da7..21803f906 100644 --- a/common/src/test/resources/BUILD.bazel +++ b/common/src/test/resources/BUILD.bazel @@ -1,3 +1,6 @@ +load("@com_google_protobuf//bazel:java_proto_library.bzl", "java_proto_library") +load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") + package( default_applicable_licenses = [ "//:license", diff --git a/common/types/BUILD.bazel b/common/types/BUILD.bazel index 76904d76b..1802b054a 100644 --- a/common/types/BUILD.bazel +++ b/common/types/BUILD.bazel @@ -39,6 +39,11 @@ java_library( exports = ["//common/src/main/java/dev/cel/common/types:cel_types"], ) +java_library( + name = "cel_proto_types", + exports = ["//common/src/main/java/dev/cel/common/types:cel_proto_types"], +) + java_library( name = "cel_v1alpha1_types", 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 22d403b6c..784e83b40 100644 --- a/compiler/src/main/java/dev/cel/compiler/BUILD.bazel +++ b/compiler/src/main/java/dev/cel/compiler/BUILD.bazel @@ -34,12 +34,13 @@ java_library( "//checker:checker_builder", "//checker:checker_legacy_environment", "//checker:proto_type_mask", + "//checker:standard_decl", "//common", "//common:compiler_common", "//common:options", "//common/annotations", "//common/internal:env_visitor", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "//parser", "//parser:macro", @@ -61,6 +62,7 @@ java_library( "//checker:checker_builder", "//checker:checker_legacy_environment", "//checker:proto_type_mask", + "//checker:standard_decl", "//common:compiler_common", "//common:options", "//common/types:type_providers", diff --git a/compiler/src/main/java/dev/cel/compiler/CelCompilerBuilder.java b/compiler/src/main/java/dev/cel/compiler/CelCompilerBuilder.java index 886667782..f64beaaba 100644 --- a/compiler/src/main/java/dev/cel/compiler/CelCompilerBuilder.java +++ b/compiler/src/main/java/dev/cel/compiler/CelCompilerBuilder.java @@ -21,6 +21,7 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FileDescriptor; +import dev.cel.checker.CelStandardDeclarations; import dev.cel.checker.ProtoTypeMask; import dev.cel.checker.TypeProvider; import dev.cel.common.CelFunctionDecl; @@ -199,6 +200,14 @@ public interface CelCompilerBuilder { @CanIgnoreReturnValue CelCompilerBuilder setStandardEnvironmentEnabled(boolean value); + /** + * Override the standard declarations for the type-checker. This can be used to subset the + * standard environment to only expose the desired declarations to the type-checker. {@link + * #setStandardEnvironmentEnabled(boolean)} must be set to false for this to take effect. + */ + @CanIgnoreReturnValue + CelCompilerBuilder setStandardDeclarations(CelStandardDeclarations standardDeclarations); + /** Adds one or more libraries for parsing and type-checking. */ @CanIgnoreReturnValue CelCompilerBuilder addLibraries(CelCompilerLibrary... libraries); diff --git a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java index 13da89f2f..83b89dfb3 100644 --- a/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java +++ b/compiler/src/main/java/dev/cel/compiler/CelCompilerImpl.java @@ -25,6 +25,7 @@ import com.google.protobuf.Descriptors.FileDescriptor; import dev.cel.checker.CelChecker; import dev.cel.checker.CelCheckerBuilder; +import dev.cel.checker.CelStandardDeclarations; import dev.cel.checker.ProtoTypeMask; import dev.cel.checker.TypeProvider; import dev.cel.common.CelAbstractSyntaxTree; @@ -36,9 +37,9 @@ import dev.cel.common.annotations.Internal; import dev.cel.common.internal.EnvVisitable; import dev.cel.common.internal.EnvVisitor; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; import dev.cel.parser.CelMacro; import dev.cel.parser.CelParser; import dev.cel.parser.CelParserBuilder; @@ -161,7 +162,7 @@ public CelCompilerBuilder setContainer(String container) { @Override public CelCompilerBuilder addVar(String name, Type type) { - return addVar(name, CelTypes.typeToCelType(type)); + return addVar(name, CelProtoTypes.typeToCelType(type)); } @Override @@ -220,7 +221,7 @@ public CelCompilerBuilder addProtoTypeMasks(Iterable typeMasks) { @Override public CelCompilerBuilder setResultType(CelType resultType) { checkNotNull(resultType); - return setProtoResultType(CelTypes.celTypeToType(resultType)); + return setProtoResultType(CelProtoTypes.celTypeToType(resultType)); } @Override @@ -278,6 +279,13 @@ public CelCompilerBuilder setStandardEnvironmentEnabled(boolean value) { return this; } + @Override + public CelCompilerBuilder setStandardDeclarations( + CelStandardDeclarations standardDeclarations) { + checkerBuilder.setStandardDeclarations(standardDeclarations); + return this; + } + @Override public CelCompilerBuilder addLibraries(CelCompilerLibrary... libraries) { checkNotNull(libraries); diff --git a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel index 57a83b955..d8fb9865d 100644 --- a/conformance/src/test/java/dev/cel/conformance/BUILD.bazel +++ b/conformance/src/test/java/dev/cel/conformance/BUILD.bazel @@ -22,6 +22,7 @@ java_library( "//common:options", "//common/internal:default_instance_message_factory", "//common/types", + "//common/types:cel_proto_types", "//common/types:type_providers", "//compiler", "//extensions", @@ -31,10 +32,9 @@ java_library( "//parser:parser_builder", "//runtime", "@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", + "@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/cel/expr/conformance/test:simple_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_extensions_truth_proto_extension", @@ -67,6 +67,7 @@ _ALL_TESTS = [ "@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/type_deduction.textproto", "@cel_spec//tests/simple:testdata/unknowns.textproto", "@cel_spec//tests/simple:testdata/wrappers.textproto", ] diff --git a/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java index 32c10bf4d..5c77bdae7 100644 --- a/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTest.java @@ -18,12 +18,11 @@ 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 dev.cel.expr.ExprValue; +import dev.cel.expr.ListValue; +import dev.cel.expr.MapValue; +import dev.cel.expr.Type; +import dev.cel.expr.Value; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -41,11 +40,14 @@ import dev.cel.common.CelOptions; import dev.cel.common.CelValidationResult; import dev.cel.common.internal.DefaultInstanceMessageFactory; +import dev.cel.common.types.CelProtoTypes; 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.common.types.TypeType; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.test.SimpleTest; import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelParser; @@ -69,8 +71,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 +80,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(); } @@ -92,7 +90,6 @@ private static TypeRegistry newDefaultTypeRegistry() { private static final CelOptions OPTIONS = CelOptions.current() .enableTimestampEpoch(true) - .enableUnsignedLongs(true) .enableHeterogeneousNumericComparisons(true) .enableProtoDifferencerEquality(true) .enableOptionalSyntax(true) @@ -133,14 +130,14 @@ private static CelParser getParser(SimpleTest test) { 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()) { + for (dev.cel.expr.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()) + .addFileTypes(dev.cel.expr.conformance.proto2.TestAllTypesExtensions.getDescriptor()) .addLibraries( CelExtensions.bindings(), CelExtensions.encoders(), @@ -148,10 +145,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 +159,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 { @@ -341,6 +334,10 @@ private static Value toValue(Object object, CelType type) throws Exception { if (object instanceof Message) { return Value.newBuilder().setObjectValue(Any.pack((Message) object)).build(); } + if (object instanceof TypeType) { + return Value.newBuilder().setTypeValue(((TypeType) object).containingTypeName()).build(); + } + throw new IllegalArgumentException( String.format("Unexpected result type: %s", object.getClass())); } @@ -378,6 +375,14 @@ public void evaluate() throws Throwable { assertThat(response.hasError()).isFalse(); response = getChecker(test).check(response.getAst()); assertThat(response.hasError()).isFalse(); + Type resultType = CelProtoTypes.celTypeToType(response.getAst().getResultType()); + + if (test.getCheckOnly()) { + assertThat(test.hasTypedResult()).isTrue(); + assertThat(resultType).isEqualTo(test.getTypedResult().getDeducedType()); + return; + } + Program program = RUNTIME.createProgram(response.getAst()); ExprValue result = null; CelEvaluationException error = null; @@ -400,6 +405,16 @@ public void evaluate() throws Throwable { assertThat(result).isNull(); assertThat(error).isNotNull(); break; + case TYPED_RESULT: + 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.getTypedResult().getResult()).build()); + assertThat(resultType).isEqualTo(test.getTypedResult().getDeducedType()); + 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 index a9f41c87f..156ad5fc5 100644 --- a/conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java +++ b/conformance/src/test/java/dev/cel/conformance/ConformanceTestRunner.java @@ -17,14 +17,14 @@ 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 dev.cel.expr.conformance.test.SimpleTest; +import dev.cel.expr.conformance.test.SimpleTestFile; +import dev.cel.expr.conformance.test.SimpleTestSection; import java.io.BufferedReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; diff --git a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java index 1a3cb196a..6abac498d 100644 --- a/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java +++ b/extensions/src/main/java/dev/cel/extensions/CelSetsExtensions.java @@ -57,7 +57,7 @@ public final class CelSetsExtensions implements CelCompilerLibrary, CelRuntimeLi "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."; + + " them are unique, so size does not factor into the 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" diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel index c2d435993..9ec11cd7c 100644 --- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel +++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel @@ -25,9 +25,8 @@ java_library( "//parser:macro", "//runtime", "//runtime:interpreter_util", - "@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", + "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_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/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 05caf8000..a1ec3f6ae 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -17,7 +17,6 @@ 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; @@ -31,6 +30,7 @@ import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; 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/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java index a0bf39e77..65b7542cd 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelMathExtensionsTest.java @@ -538,7 +538,7 @@ public void least_unsignedLongResult_withSignedLongType_success(String expr, lon + " '3'}") public void least_unsignedLongResult_withUnsignedLongType_success( String expr, String expectedResult) throws Exception { - CelOptions celOptions = CelOptions.current().enableUnsignedLongs(true).build(); + CelOptions celOptions = CelOptions.current().build(); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .setOptions(celOptions) diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java index c877555c2..06f748a47 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java @@ -17,9 +17,6 @@ import static com.google.common.truth.Truth.assertThat; 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; @@ -45,6 +42,9 @@ import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; +import dev.cel.common.types.TypeType; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; @@ -91,10 +91,9 @@ private enum ConstantTestCases { private static CelBuilder newCelBuilder() { return CelFactory.standardCelBuilder() - .setOptions( - CelOptions.current().enableUnsignedLongs(true).enableTimestampEpoch(true).build()) + .setOptions(CelOptions.current().enableTimestampEpoch(true).build()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .setContainer("google.api.expr.test.v1.proto2") + .setContainer("cel.expr.conformance.proto3") .addMessageTypes(TestAllTypes.getDescriptor()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) .addCompilerLibraries(CelOptionalLibrary.INSTANCE); @@ -1439,11 +1438,12 @@ public void optionalFlatMapMacro_withNonIdent_throws() { @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()); + TypeType optionalRuntimeType = (TypeType) cel.createProgram(ast).eval(); + + assertThat(optionalRuntimeType.name()).isEqualTo("type"); + assertThat(optionalRuntimeType.containingTypeName()).isEqualTo("optional_type"); } @Test diff --git a/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java index 530ba73ae..e7d58574b 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelProtoExtensionsTest.java @@ -17,10 +17,6 @@ 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,6 +35,10 @@ import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto2.Proto2ExtensionScopedMessage; +import dev.cel.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypes.NestedEnum; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; @@ -54,8 +54,8 @@ public final class CelProtoExtensionsTest { .addLibraries(CelExtensions.protos()) .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .addFileTypes(TestAllTypesExtensions.getDescriptor()) - .addVar("msg", StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes")) - .setContainer("google.api.expr.test.v1.proto2") + .addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes")) + .setContainer("cel.expr.conformance.proto2") .build(); private static final CelRuntime CEL_RUNTIME = @@ -85,12 +85,12 @@ public final class CelProtoExtensionsTest { .build(); @Test - @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, cel.expr.conformance.proto2.int32_ext)'}") + @TestParameters("{expr: 'proto.hasExt(msg, cel.expr.conformance.proto2.nested_ext)'}") + @TestParameters("{expr: 'proto.hasExt(msg, cel.expr.conformance.proto2.nested_enum_ext)'}") @TestParameters( - "{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)'}") + "{expr: 'proto.hasExt(msg, cel.expr.conformance.proto2.repeated_test_all_types)'}") + @TestParameters("{expr: '!proto.hasExt(msg, cel.expr.conformance.proto2.test_all_types_ext)'}") public void hasExt_packageScoped_success(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -103,16 +103,16 @@ public void hasExt_packageScoped_success(String expr) throws Exception { @Test @TestParameters( "{expr: 'proto.hasExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)'}") + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)'}") @TestParameters( "{expr: 'proto.hasExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext)'}") + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.int64_ext)'}") @TestParameters( "{expr: '!proto.hasExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types)'}") + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_repeated_test_all_types)'}") @TestParameters( "{expr: '!proto.hasExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.nested_enum_ext)'}") + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.nested_enum_ext)'}") public void hasExt_messageScoped_success(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -123,11 +123,11 @@ public void hasExt_messageScoped_success(String expr) throws Exception { } @Test - @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)'}") + @TestParameters("{expr: 'msg.hasExt(''cel.expr.conformance.proto2.int32_ext'', 0)'}") + @TestParameters("{expr: 'dyn(msg).hasExt(''cel.expr.conformance.proto2.int32_ext'', 0)'}") public void hasExt_nonProtoNamespace_success(String expr) throws Exception { StructTypeReference proto2MessageTypeReference = - StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes"); + StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelExtensions.protos()) @@ -170,24 +170,24 @@ public void hasExt_undefinedField_throwsException() { CelValidationException.class, () -> CEL_COMPILER - .compile("!proto.hasExt(msg, google.api.expr.test.v1.proto2.undefined_field)") + .compile("!proto.hasExt(msg, cel.expr.conformance.proto2.undefined_field)") .getAst()); assertThat(exception) .hasMessageThat() - .contains("undefined field 'google.api.expr.test.v1.proto2.undefined_field'"); + .contains("undefined field 'cel.expr.conformance.proto2.undefined_field'"); } @Test - @TestParameters("{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.int32_ext) == 1'}") + @TestParameters("{expr: 'proto.getExt(msg, cel.expr.conformance.proto2.int32_ext) == 1'}") @TestParameters( - "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.nested_ext) ==" + "{expr: 'proto.getExt(msg, cel.expr.conformance.proto2.nested_ext) ==" + " TestAllTypes{single_int32: 5}'}") @TestParameters( - "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.nested_enum_ext) ==" + "{expr: 'proto.getExt(msg, cel.expr.conformance.proto2.nested_enum_ext) ==" + " TestAllTypes.NestedEnum.BAR'}") @TestParameters( - "{expr: 'proto.getExt(msg, google.api.expr.test.v1.proto2.repeated_test_all_types) ==" + "{expr: 'proto.getExt(msg, cel.expr.conformance.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(); @@ -201,11 +201,11 @@ public void getExt_packageScoped_success(String expr) throws Exception { @Test @TestParameters( "{expr: 'proto.getExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)" + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.message_scoped_nested_ext)" + " == TestAllTypes{single_string: ''test''}'}") @TestParameters( "{expr: 'proto.getExt(msg," - + " google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext) == 1'}") + + " cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.int64_ext) == 1'}") public void getExt_messageScopedSuccess(String expr) throws Exception { CelAbstractSyntaxTree ast = CEL_COMPILER.compile(expr).getAst(); boolean result = @@ -222,20 +222,20 @@ public void getExt_undefinedField_throwsException() { CelValidationException.class, () -> CEL_COMPILER - .compile("!proto.getExt(msg, google.api.expr.test.v1.proto2.undefined_field)") + .compile("!proto.getExt(msg, cel.expr.conformance.proto2.undefined_field)") .getAst()); assertThat(exception) .hasMessageThat() - .contains("undefined field 'google.api.expr.test.v1.proto2.undefined_field'"); + .contains("undefined field 'cel.expr.conformance.proto2.undefined_field'"); } @Test - @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'}") + @TestParameters("{expr: 'msg.getExt(''cel.expr.conformance.proto2.int32_ext'', 0) == 1'}") + @TestParameters("{expr: 'dyn(msg).getExt(''cel.expr.conformance.proto2.int32_ext'', 0) == 1'}") public void getExt_nonProtoNamespace_success(String expr) throws Exception { StructTypeReference proto2MessageTypeReference = - StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes"); + StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"); CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder() .addLibraries(CelExtensions.protos()) @@ -284,11 +284,10 @@ public void getExt_onAnyPackedExtensionField_success() throws Exception { .addCompilerLibraries(CelExtensions.protos()) .addFileTypes(TestAllTypesExtensions.getDescriptor()) .setExtensionRegistry(extensionRegistry) - .addVar( - "msg", StructTypeReference.create("google.api.expr.test.v1.proto2.TestAllTypes")) + .addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes")) .build(); CelAbstractSyntaxTree ast = - cel.compile("proto.getExt(msg, google.api.expr.test.v1.proto2.int32_ext)").getAst(); + cel.compile("proto.getExt(msg, cel.expr.conformance.proto2.int32_ext)").getAst(); Any anyMsg = Any.pack( TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build()); @@ -311,10 +310,10 @@ private enum ParseErrorTestCase { + " | ...................................................^"), FIELD_INSIDE_PRESENCE_TEST( "proto.getExt(Proto2ExtensionScopedMessage{}," - + " has(google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext))", + + " has(cel.expr.conformance.proto2.Proto2ExtensionScopedMessage.int64_ext))", "ERROR: :1:49: invalid extension field\n" + " | proto.getExt(Proto2ExtensionScopedMessage{}," - + " has(google.api.expr.test.v1.proto2.Proto2ExtensionScopedMessage.int64_ext))\n" + + " has(cel.expr.conformance.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 ef11ff658..808cc50f8 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelSetsExtensionsTest.java @@ -17,7 +17,6 @@ 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; @@ -32,6 +31,7 @@ import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelSetsExtensions.Function; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; @@ -43,13 +43,12 @@ @RunWith(TestParameterInjector.class) public final class CelSetsExtensionsTest { - private static final CelOptions CEL_OPTIONS = - CelOptions.current().enableUnsignedLongs(true).build(); + private static final CelOptions CEL_OPTIONS = CelOptions.current().build(); private static final CelCompiler COMPILER = CelCompilerFactory.standardCelCompilerBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) .setOptions(CEL_OPTIONS) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .addLibraries(CelExtensions.sets(CEL_OPTIONS)) .addVar("list", ListType.create(SimpleType.INT)) .addVar("subList", ListType.create(SimpleType.INT)) 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..8a27272ca 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", @@ -74,7 +73,7 @@ java_library( ], visibility = ["//visibility:private"], deps = [ - "//checker:checker_legacy_environment", + "//checker:standard_decl", "//extensions", "//extensions:optional_library", "//parser:operator", 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/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java b/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java index 07a3f062b..35608a776 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/DefaultOptimizerConstants.java @@ -19,7 +19,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; -import dev.cel.checker.Standard; +import dev.cel.checker.CelStandardDeclarations; import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.extensions.CelOptionalLibrary.Function; @@ -37,10 +37,10 @@ final class DefaultOptimizerConstants { */ static final ImmutableSet CEL_CANONICAL_FUNCTIONS = ImmutableSet.builder() + .addAll(CelStandardDeclarations.getAllFunctionNames()) .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()) 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 ff3162cf4..b0346267c 100644 --- a/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java +++ b/optimizer/src/main/java/dev/cel/optimizer/optimizers/SubexpressionOptimizer.java @@ -556,10 +556,6 @@ && containsEliminableFunctionOnly(navigableExpr) } private boolean containsComprehensionIdentInSubexpr(CelNavigableMutableExpr navExpr) { - if (!cseOptions.retainComprehensionStructure()) { - return true; - } - if (navExpr.getKind().equals(Kind.COMPREHENSION)) { return true; } @@ -672,8 +668,6 @@ public abstract static class SubexpressionOptimizerOptions { public abstract boolean enableCelBlock(); - public abstract boolean retainComprehensionStructure(); - public abstract int subexpressionMaxRecursionDepth(); public abstract ImmutableSet eliminableFunctions(); @@ -730,25 +724,6 @@ 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(); /** @@ -783,7 +758,6 @@ public static Builder newBuilder() { .iterationLimit(500) .populateMacroCalls(false) .enableCelBlock(false) - .retainComprehensionStructure(true) .subexpressionMaxRecursionDepth(0); } diff --git a/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java b/optimizer/src/test/java/dev/cel/optimizer/AstMutatorTest.java index 3a3983747..da8b53fc3 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.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; @@ -45,6 +44,7 @@ import dev.cel.common.navigation.CelNavigableMutableExpr; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; @@ -64,7 +64,7 @@ public class AstMutatorTest { .addMessageTypes(TestAllTypes.getDescriptor()) .addCompilerLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.bindings()) .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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 9dd7d616d..712247ae5 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel @@ -33,7 +33,7 @@ java_library( "//parser:operator", "//parser:unparser", "//runtime", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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 92ef80377..f378c6d44 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/BUILD.bazel @@ -33,7 +33,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", + "@cel_spec//proto/cel/expr/conformance/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 b416eb2d5..14aabe50c 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/ConstantFoldingOptimizerTest.java @@ -17,7 +17,6 @@ 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; @@ -30,6 +29,7 @@ import dev.cel.common.types.ListType; import dev.cel.common.types.MapType; import dev.cel.common.types.SimpleType; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.optimizer.CelOptimizationException; @@ -58,7 +58,7 @@ public class ConstantFoldingOptimizerTest { .addFunctionBindings( CelFunctionBinding.from("get_true_overload", ImmutableList.of(), unused -> true)) .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.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 1f7de0a7e..794af6802 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerBaselineTest.java @@ -17,8 +17,6 @@ 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; @@ -33,6 +31,8 @@ import dev.cel.common.types.OptionalType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; +import dev.cel.expr.conformance.proto3.NestedTestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelExtensions; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.optimizer.CelOptimizer; @@ -71,7 +71,6 @@ public class SubexpressionOptimizerBaselineTest extends BaselineTestCase { private static final SubexpressionOptimizerOptions OPTIMIZER_COMMON_OPTIONS = SubexpressionOptimizerOptions.newBuilder() - .retainComprehensionStructure(false) .populateMacroCalls(true) .enableCelBlock(true) .addEliminableFunctions("pure_custom_func") @@ -259,7 +258,6 @@ public void large_expressions_block_recursion_depth_1() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) - .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(1) .build()); @@ -274,7 +272,6 @@ public void large_expressions_block_recursion_depth_2() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) - .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(2) .build()); @@ -289,7 +286,6 @@ public void large_expressions_block_recursion_depth_3() throws Exception { CEL, SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) - .retainComprehensionStructure(false) .enableCelBlock(true) .subexpressionMaxRecursionDepth(3) .build()); @@ -323,7 +319,7 @@ private void runLargeTestCases(CelOptimizer celOptimizer) throws Exception { private static CelBuilder newCelBuilder() { return CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .setOptions( CelOptions.current().enableTimestampEpoch(true).populateMacroCalls(true).build()) @@ -356,8 +352,6 @@ 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 2f196b292..84515f0d6 100644 --- a/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java +++ b/optimizer/src/test/java/dev/cel/optimizer/optimizers/SubexpressionOptimizerTest.java @@ -18,7 +18,6 @@ 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; @@ -46,6 +45,7 @@ import dev.cel.common.types.ListType; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelExtensions; import dev.cel.optimizer.CelOptimizationException; import dev.cel.optimizer.CelOptimizer; @@ -210,7 +210,6 @@ public void cse_withComprehensionStructureRetained() throws Exception { SubexpressionOptimizerOptions.newBuilder() .populateMacroCalls(true) .enableCelBlock(true) - .retainComprehensionStructure(true) .build()); CelAbstractSyntaxTree optimizedAst = celOptimizer.optimize(ast); diff --git a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline index 54207adf1..cf0011868 100644 --- a/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/constfold_before_subexpression_unparsed.baseline @@ -4,7 +4,6 @@ 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 @@ -21,7 +20,6 @@ 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 @@ -38,7 +36,6 @@ 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 @@ -55,7 +52,6 @@ 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 @@ -72,7 +68,6 @@ 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 @@ -89,7 +84,6 @@ 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 @@ -106,7 +100,6 @@ 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}) @@ -123,7 +116,6 @@ 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]) @@ -140,7 +132,6 @@ 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) @@ -157,7 +148,6 @@ 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) @@ -174,7 +164,6 @@ 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 @@ -191,7 +180,6 @@ 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) @@ -208,7 +196,6 @@ 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) @@ -225,7 +212,6 @@ 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) @@ -242,7 +228,6 @@ 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) @@ -259,7 +244,6 @@ 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) @@ -276,7 +260,6 @@ 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) @@ -293,7 +276,6 @@ 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 @@ -310,7 +292,6 @@ 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 @@ -327,7 +308,6 @@ 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 @@ -344,7 +324,6 @@ 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 @@ -361,7 +340,6 @@ 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 @@ -378,7 +356,6 @@ 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 @@ -395,7 +372,6 @@ 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 @@ -412,7 +388,6 @@ 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 @@ -429,7 +404,6 @@ 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 @@ -446,11 +420,10 @@ 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) -[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_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2]], @index3.exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, [@index1]], @index2.exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5]], @index1.exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @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) @@ -463,7 +436,6 @@ 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]]) @@ -480,7 +452,6 @@ 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 @@ -497,7 +468,6 @@ 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 @@ -514,7 +484,6 @@ 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) @@ -531,7 +500,6 @@ 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) @@ -548,7 +516,6 @@ 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) @@ -565,7 +532,6 @@ 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) @@ -582,7 +548,6 @@ 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]) @@ -599,7 +564,6 @@ 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 @@ -616,7 +580,6 @@ 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 @@ -633,7 +596,6 @@ 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 @@ -650,7 +612,6 @@ 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 @@ -667,7 +628,6 @@ 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 @@ -684,7 +644,6 @@ 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 @@ -701,7 +660,6 @@ 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 @@ -718,7 +676,6 @@ 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)) @@ -735,7 +692,6 @@ 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/large_expressions_block_recursion_depth_1.baseline b/optimizer/src/test/resources/large_expressions_block_recursion_depth_1.baseline index 8dd1445eb..57e109c22 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], @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 +Unparsed: cel.@block([[1, 2, 3], [@index0]], @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 f139abe3c..1cbd1d4e7 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], @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 +Unparsed: cel.@block([[1, 2, 3], [@index0], @index0.map(@it:7:0, @index0), [@index2], @index0.map(@it:6:0, @index2), [@index4], @index0.map(@it:5:0, @index4), [@index6], @index0.map(@it:4:0, @index6), [@index8], @index0.map(@it:3:0, @index8), [@index10], @index0.map(@it:2:0, @index10), [@index12], @index0.map(@it:1:0, @index12), [@index14]], @index0.map(@it:0:0, @index14)) \ 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 292b584f6..61dc23350 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,163 +1116,169 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } - } - } - 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 [11] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + 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 } } - result: { - IDENT [17] { - 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 [18] { + CALL [16] { function: size args: { - LIST [19] { + LIST [17] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } + 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 } } - result: { - IDENT [32] { - 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 [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index1 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index1 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1285,158 +1291,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { + LIST [16] { elements: { - 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 } + IDENT [17] { + name: @index0 + } + } + } + COMPREHENSION [18] { + iter_var: @it:0:1 + iter_range: { + LIST [19] { + elements: { + CONSTANT [20] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [21] { value: false } + } + loop_condition: { + CALL [22] { + function: @not_strictly_false + args: { + CALL [23] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [24] { + name: @ac:0:1 } } } } - loop_step: { - CALL [25] { - function: _||_ + } + } + loop_step: { + CALL [25] { + function: _||_ + args: { + IDENT [26] { + name: @ac:0:1 + } + CALL [27] { + function: _==_ args: { - IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + IDENT [28] { + name: @it:0:1 } + CONSTANT [29] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [30] { + name: @ac:0:1 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index2 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index1 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index1 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1504,63 +1516,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1569,37 +1564,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1608,12 +1617,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -2356,74 +2379,59 @@ CALL [1] { 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: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } +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" } } } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } } } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } - } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { + LIST [16] { elements: { - } - } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { + LIST [6] { elements: { - LIST [19] { - elements: { - IDENT [20] { - name: @index0 + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 } - IDENT [21] { - name: @index0 + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 } } } @@ -2432,39 +2440,55 @@ CALL [1] { } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } } } - accu_var: @ac:0:0 - accu_init: { - LIST [23] { - elements: { - } + result: { + IDENT [18] { + name: @ac:1:0 } } - loop_condition: { - CONSTANT [24] { value: true } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { } - loop_step: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - LIST [27] { + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { elements: { - LIST [28] { - elements: { - IDENT [29] { - name: @index1 + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 } - IDENT [30] { - name: @index1 + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 } } } @@ -2473,11 +2497,11 @@ CALL [1] { } } } - result: { - IDENT [31] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [34] { + 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 070df4db9..5bce4d49a 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,89 +1436,49 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:0 - } - IDENT [10] { - name: @index1 - } - } - } - LIST [11] { + LIST [5] { elements: { - CONSTANT [12] { value: 2 } - } - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 1 } - } - } - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @ac:0:0 - } - IDENT [18] { - name: @index4 - } + CONSTANT [6] { value: 2 } } } } } - CALL [19] { + CALL [7] { function: _==_ args: { - CALL [20] { + CALL [8] { function: _+_ args: { - CALL [21] { + CALL [9] { function: _+_ args: { - CALL [22] { + CALL [10] { function: _+_ args: { - CALL [23] { + CALL [11] { function: size args: { - LIST [24] { + LIST [12] { elements: { - COMPREHENSION [25] { + COMPREHENSION [13] { iter_var: @it:0:0 iter_range: { - IDENT [26] { + IDENT [14] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [27] { value: false } + CONSTANT [15] { value: false } } loop_condition: { - CALL [28] { + CALL [16] { function: @not_strictly_false args: { - CALL [29] { + CALL [17] { function: !_ args: { - IDENT [30] { + IDENT [18] { name: @ac:0:0 } } @@ -1527,12 +1487,26 @@ CALL [1] { } } loop_step: { - IDENT [31] { - name: @index2 + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @ac:0:0 + } + CALL [21] { + function: _>_ + args: { + IDENT [22] { + name: @it:0:0 + } + CONSTANT [23] { value: 0 } + } + } + } } } result: { - IDENT [32] { + IDENT [24] { name: @ac:0:0 } } @@ -1541,30 +1515,30 @@ CALL [1] { } } } - CALL [33] { + CALL [25] { function: size args: { - LIST [34] { + LIST [26] { elements: { - COMPREHENSION [35] { + COMPREHENSION [27] { iter_var: @it:0:0 iter_range: { - IDENT [36] { + IDENT [28] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [37] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [38] { + CALL [30] { function: @not_strictly_false args: { - CALL [39] { + CALL [31] { function: !_ args: { - IDENT [40] { + IDENT [32] { name: @ac:0:0 } } @@ -1573,12 +1547,26 @@ CALL [1] { } } loop_step: { - IDENT [41] { - name: @index2 + CALL [33] { + function: _||_ + args: { + IDENT [34] { + name: @ac:0:0 + } + CALL [35] { + function: _>_ + args: { + IDENT [36] { + name: @it:0:0 + } + CONSTANT [37] { value: 0 } + } + } + } } } result: { - IDENT [42] { + IDENT [38] { name: @ac:0:0 } } @@ -1589,30 +1577,30 @@ CALL [1] { } } } - CALL [43] { + CALL [39] { function: size args: { - LIST [44] { + LIST [40] { elements: { - COMPREHENSION [45] { + COMPREHENSION [41] { iter_var: @it:0:0 iter_range: { - IDENT [46] { - name: @index3 + IDENT [42] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [47] { value: false } + CONSTANT [43] { value: false } } loop_condition: { - CALL [48] { + CALL [44] { function: @not_strictly_false args: { - CALL [49] { + CALL [45] { function: !_ args: { - IDENT [50] { + IDENT [46] { name: @ac:0:0 } } @@ -1621,8 +1609,22 @@ CALL [1] { } } loop_step: { - IDENT [51] { - name: @index5 + CALL [47] { + function: _||_ + args: { + IDENT [48] { + name: @ac:0:0 + } + CALL [49] { + function: _>_ + args: { + IDENT [50] { + name: @it:0:0 + } + CONSTANT [51] { value: 1 } + } + } + } } } result: { @@ -1646,7 +1648,7 @@ CALL [1] { iter_var: @it:0:0 iter_range: { IDENT [56] { - name: @index3 + name: @index1 } } accu_var: @ac:0:0 @@ -1669,12 +1671,26 @@ CALL [1] { } } loop_step: { - IDENT [61] { - name: @index5 + CALL [61] { + function: _||_ + args: { + IDENT [62] { + name: @ac:0:0 + } + CALL [63] { + function: _>_ + args: { + IDENT [64] { + name: @it:0:0 + } + CONSTANT [65] { value: 1 } + } + } + } } } result: { - IDENT [62] { + IDENT [66] { name: @ac:0:0 } } @@ -1685,7 +1701,7 @@ CALL [1] { } } } - CONSTANT [63] { value: 4 } + CONSTANT [67] { value: 4 } } } } @@ -1703,94 +1719,54 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:0 - } - IDENT [10] { - name: @index1 - } - } - } - LIST [11] { + LIST [5] { elements: { - CONSTANT [12] { value: "a" } - } - } - CALL [13] { - function: _==_ - args: { - IDENT [14] { - name: @it:0:1 - } - CONSTANT [15] { value: "a" } + CONSTANT [6] { value: "a" } } } - CALL [16] { - function: _||_ - args: { - IDENT [17] { - name: @ac:0:1 - } - IDENT [18] { - name: @index4 - } - } - } - LIST [19] { + LIST [7] { elements: { - CONSTANT [20] { value: true } - CONSTANT [21] { value: true } - CONSTANT [22] { value: true } - CONSTANT [23] { value: true } + CONSTANT [8] { value: true } + CONSTANT [9] { value: true } + CONSTANT [10] { value: true } + CONSTANT [11] { value: true } } } } } - CALL [24] { + CALL [12] { function: _==_ args: { - CALL [25] { + CALL [13] { function: _+_ args: { - CALL [26] { + CALL [14] { function: _+_ args: { - CALL [27] { + CALL [15] { function: _+_ args: { - LIST [28] { + LIST [16] { elements: { - COMPREHENSION [29] { + COMPREHENSION [17] { iter_var: @it:0:0 iter_range: { - IDENT [30] { + IDENT [18] { name: @index0 } } accu_var: @ac:0:0 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: @ac:0:0 } } @@ -1799,39 +1775,53 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index2 + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 + } + CONSTANT [27] { value: 0 } + } + } + } } } result: { - IDENT [36] { + IDENT [28] { name: @ac:0:0 } } } } } - LIST [37] { + LIST [29] { elements: { - COMPREHENSION [38] { + COMPREHENSION [30] { iter_var: @it:0:0 iter_range: { - IDENT [39] { + IDENT [31] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [40] { value: false } + CONSTANT [32] { value: false } } loop_condition: { - CALL [41] { + CALL [33] { function: @not_strictly_false args: { - CALL [42] { + CALL [34] { function: !_ args: { - IDENT [43] { + IDENT [35] { name: @ac:0:0 } } @@ -1840,12 +1830,26 @@ CALL [1] { } } loop_step: { - IDENT [44] { - name: @index2 + CALL [36] { + function: _||_ + args: { + IDENT [37] { + name: @ac:0:0 + } + CALL [38] { + function: _>_ + args: { + IDENT [39] { + name: @it:0:0 + } + CONSTANT [40] { value: 0 } + } + } + } } } result: { - IDENT [45] { + IDENT [41] { name: @ac:0:0 } } @@ -1854,27 +1858,27 @@ CALL [1] { } } } - LIST [46] { + LIST [42] { elements: { - COMPREHENSION [47] { + COMPREHENSION [43] { iter_var: @it:0:1 iter_range: { - IDENT [48] { - name: @index3 + IDENT [44] { + name: @index1 } } accu_var: @ac:0:1 accu_init: { - CONSTANT [49] { value: false } + CONSTANT [45] { value: false } } loop_condition: { - CALL [50] { + CALL [46] { function: @not_strictly_false args: { - CALL [51] { + CALL [47] { function: !_ args: { - IDENT [52] { + IDENT [48] { name: @ac:0:1 } } @@ -1883,8 +1887,22 @@ CALL [1] { } } loop_step: { - IDENT [53] { - name: @index5 + CALL [49] { + function: _||_ + args: { + IDENT [50] { + name: @ac:0:1 + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @it:0:1 + } + CONSTANT [53] { value: "a" } + } + } + } } } result: { @@ -1903,7 +1921,7 @@ CALL [1] { iter_var: @it:0:1 iter_range: { IDENT [57] { - name: @index3 + name: @index1 } } accu_var: @ac:0:1 @@ -1926,12 +1944,26 @@ CALL [1] { } } loop_step: { - IDENT [62] { - name: @index5 + CALL [62] { + function: _||_ + args: { + IDENT [63] { + name: @ac:0:1 + } + CALL [64] { + function: _==_ + args: { + IDENT [65] { + name: @it:0:1 + } + CONSTANT [66] { value: "a" } + } + } + } } } result: { - IDENT [63] { + IDENT [67] { name: @ac:0:1 } } @@ -1940,8 +1972,8 @@ CALL [1] { } } } - IDENT [64] { - name: @index6 + IDENT [68] { + name: @index2 } } } @@ -1960,78 +1992,38 @@ CALL [1] { CONSTANT [4] { value: 1 } } } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:0 - } - IDENT [10] { - name: @index1 - } - } - } - CALL [11] { - function: _>_ - args: { - IDENT [12] { - name: @it:0:0 - } - CONSTANT [13] { value: 1 } - } - } - CALL [14] { - function: _||_ - args: { - IDENT [15] { - name: @ac:0:0 - } - IDENT [16] { - name: @index3 - } - } - } - LIST [17] { + LIST [5] { elements: { - CONSTANT [18] { value: 2 } + CONSTANT [6] { value: 2 } } } } } - CALL [19] { + CALL [7] { function: _&&_ args: { - CALL [20] { + CALL [8] { function: _&&_ args: { - COMPREHENSION [21] { + COMPREHENSION [9] { iter_var: @it:0:0 iter_range: { - IDENT [22] { + IDENT [10] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [23] { value: false } + CONSTANT [11] { value: false } } loop_condition: { - CALL [24] { + CALL [12] { function: @not_strictly_false args: { - CALL [25] { + CALL [13] { function: !_ args: { - IDENT [26] { + IDENT [14] { name: @ac:0:0 } } @@ -2040,35 +2032,49 @@ CALL [1] { } } loop_step: { - IDENT [27] { - name: @index2 + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @ac:0:0 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @it:0:0 + } + CONSTANT [19] { value: 0 } + } + } + } } } result: { - IDENT [28] { + IDENT [20] { name: @ac:0:0 } } } - COMPREHENSION [29] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - IDENT [30] { + IDENT [22] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [31] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [32] { + CALL [24] { function: @not_strictly_false args: { - CALL [33] { + CALL [25] { function: !_ args: { - IDENT [34] { + IDENT [26] { name: @ac:0:0 } } @@ -2077,40 +2083,54 @@ CALL [1] { } } loop_step: { - IDENT [35] { - name: @index2 + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @ac:0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @it:0:0 + } + CONSTANT [31] { value: 0 } + } + } + } } } result: { - IDENT [36] { + IDENT [32] { name: @ac:0:0 } } } } } - CALL [37] { + CALL [33] { function: _&&_ args: { - COMPREHENSION [38] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - IDENT [39] { + IDENT [35] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [40] { value: false } + CONSTANT [36] { value: false } } loop_condition: { - CALL [41] { + CALL [37] { function: @not_strictly_false args: { - CALL [42] { + CALL [38] { function: !_ args: { - IDENT [43] { + IDENT [39] { name: @ac:0:0 } } @@ -2119,8 +2139,22 @@ CALL [1] { } } loop_step: { - IDENT [44] { - name: @index4 + CALL [40] { + function: _||_ + args: { + IDENT [41] { + name: @ac:0:0 + } + CALL [42] { + function: _>_ + args: { + IDENT [43] { + name: @it:0:0 + } + CONSTANT [44] { value: 1 } + } + } + } } } result: { @@ -2133,7 +2167,7 @@ CALL [1] { iter_var: @it:0:0 iter_range: { IDENT [47] { - name: @index5 + name: @index1 } } accu_var: @ac:0:0 @@ -2156,12 +2190,26 @@ CALL [1] { } } loop_step: { - IDENT [52] { - name: @index4 + CALL [52] { + function: _||_ + args: { + IDENT [53] { + name: @ac:0:0 + } + CALL [54] { + function: _>_ + args: { + IDENT [55] { + name: @it:0:0 + } + CONSTANT [56] { value: 1 } + } + } + } } } result: { - IDENT [53] { + IDENT [57] { name: @ac:0:0 } } @@ -2194,101 +2242,92 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CALL [11] { - function: _+_ - args: { - IDENT [12] { - name: @it:1:0 - } - CONSTANT [13] { value: 1 } - } - } - LIST [14] { - elements: { - IDENT [15] { - name: @index2 - } - } - } - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - IDENT [18] { - name: @index3 - } - } - } - LIST [19] { + LIST [11] { elements: { - IDENT [20] { + IDENT [12] { name: @index1 } - IDENT [21] { + IDENT [13] { name: @index1 } - IDENT [22] { + IDENT [14] { name: @index1 } } } } } - CALL [23] { + CALL [15] { function: _==_ args: { - COMPREHENSION [24] { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - IDENT [25] { + IDENT [17] { name: @index0 } } 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] { + IDENT [21] { name: @ac:0:0 } - LIST [30] { + LIST [22] { elements: { - COMPREHENSION [31] { + COMPREHENSION [23] { iter_var: @it:1:0 iter_range: { - IDENT [32] { + IDENT [24] { name: @index0 } } 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] { - name: @index4 + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @ac:1:0 + } + LIST [29] { + elements: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @it:1:0 + } + CONSTANT [32] { value: 1 } + } + } + } + } + } } } result: { - IDENT [36] { + IDENT [33] { name: @ac:1:0 } } @@ -2299,13 +2338,13 @@ CALL [1] { } } result: { - IDENT [37] { + IDENT [34] { name: @ac:0:0 } } } - IDENT [38] { - name: @index5 + IDENT [35] { + name: @index2 } } } @@ -2332,124 +2371,112 @@ CALL [1] { CONSTANT [9] { value: 3 } } } - CALL [10] { - function: _==_ - args: { - IDENT [11] { - name: @it:1:0 - } - IDENT [12] { - name: @it:0:0 - } - } - } - LIST [13] { - elements: { - IDENT [14] { - name: @it:1:0 - } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @ac:1:0 - } - IDENT [17] { - name: @index3 - } - } - } - CALL [18] { - function: _?_:_ - args: { - IDENT [19] { - name: @index2 - } - IDENT [20] { - name: @index4 - } - IDENT [21] { - name: @ac:1:0 - } - } - } - LIST [22] { + LIST [10] { elements: { - CONSTANT [23] { value: 1 } + CONSTANT [11] { value: 1 } } } - LIST [24] { + LIST [12] { elements: { - CONSTANT [25] { value: 2 } + CONSTANT [13] { value: 2 } } } - LIST [26] { + LIST [14] { elements: { - IDENT [27] { - name: @index6 + IDENT [15] { + name: @index2 } - IDENT [28] { - name: @index7 + IDENT [16] { + name: @index3 } } } } } - CALL [29] { + CALL [17] { function: _==_ args: { - COMPREHENSION [30] { + COMPREHENSION [18] { iter_var: @it:0:0 iter_range: { - IDENT [31] { + IDENT [19] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [32] { + LIST [20] { elements: { } } } loop_condition: { - CONSTANT [33] { value: true } + CONSTANT [21] { value: true } } loop_step: { - CALL [34] { + CALL [22] { function: _+_ args: { - IDENT [35] { + IDENT [23] { name: @ac:0:0 } - LIST [36] { + LIST [24] { elements: { - COMPREHENSION [37] { + COMPREHENSION [25] { iter_var: @it:1:0 iter_range: { - IDENT [38] { + IDENT [26] { name: @index1 } } accu_var: @ac:1:0 accu_init: { - LIST [39] { + LIST [27] { elements: { } } } loop_condition: { - CONSTANT [40] { value: true } + CONSTANT [28] { value: true } } loop_step: { - IDENT [41] { - name: @index5 + CALL [29] { + function: _?_:_ + args: { + CALL [30] { + function: _==_ + args: { + IDENT [31] { + name: @it:1:0 + } + IDENT [32] { + name: @it:0:0 + } + } + } + CALL [33] { + function: _+_ + args: { + IDENT [34] { + name: @ac:1:0 + } + LIST [35] { + elements: { + IDENT [36] { + name: @it:1:0 + } + } + } + } + } + IDENT [37] { + name: @ac:1:0 + } + } } } result: { - IDENT [42] { + IDENT [38] { name: @ac:1:0 } } @@ -2460,13 +2487,13 @@ CALL [1] { } } result: { - IDENT [43] { + IDENT [39] { name: @ac:0:0 } } } - IDENT [44] { - name: @index8 + IDENT [40] { + name: @index4 } } } @@ -2487,88 +2514,79 @@ CALL [1] { CONSTANT [6] { value: 3 } } } - CALL [7] { - function: _+_ - args: { - IDENT [8] { - name: @it:1:0 - } - CONSTANT [9] { value: 1 } - } - } - LIST [10] { - elements: { - IDENT [11] { - name: @index1 - } - } - } - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @ac:1:0 - } - IDENT [14] { - name: @index2 - } - } - } } } - CALL [15] { + CALL [7] { function: _==_ args: { - COMPREHENSION [16] { + COMPREHENSION [8] { iter_var: @it:0:0 iter_range: { - IDENT [17] { + IDENT [9] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [18] { + LIST [10] { elements: { } } } loop_condition: { - CONSTANT [19] { value: true } + CONSTANT [11] { value: true } } loop_step: { - CALL [20] { + CALL [12] { function: _+_ args: { - IDENT [21] { + IDENT [13] { name: @ac:0:0 } - LIST [22] { + LIST [14] { elements: { - COMPREHENSION [23] { + COMPREHENSION [15] { iter_var: @it:1:0 iter_range: { - IDENT [24] { + IDENT [16] { name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [25] { + LIST [17] { elements: { } } } loop_condition: { - CONSTANT [26] { value: true } + CONSTANT [18] { value: true } } loop_step: { - IDENT [27] { - name: @index3 + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @ac:1:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @it:1:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } } } result: { - IDENT [28] { + IDENT [25] { name: @ac:1:0 } } @@ -2579,61 +2597,79 @@ CALL [1] { } } result: { - IDENT [29] { + IDENT [26] { name: @ac:0:0 } } } - COMPREHENSION [30] { + COMPREHENSION [27] { iter_var: @it:0:0 iter_range: { - IDENT [31] { + IDENT [28] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [32] { + LIST [29] { elements: { } } } loop_condition: { - CONSTANT [33] { value: true } + CONSTANT [30] { value: true } } loop_step: { - CALL [34] { + CALL [31] { function: _+_ args: { - IDENT [35] { + IDENT [32] { name: @ac:0:0 } - LIST [36] { + LIST [33] { elements: { - COMPREHENSION [37] { + COMPREHENSION [34] { iter_var: @it:1:0 iter_range: { - IDENT [38] { + IDENT [35] { name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [39] { + LIST [36] { elements: { } } } loop_condition: { - CONSTANT [40] { value: true } + CONSTANT [37] { value: true } } loop_step: { - IDENT [41] { - name: @index3 + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @ac:1:0 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @it:1:0 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } } } result: { - IDENT [42] { + IDENT [44] { name: @ac:1:0 } } @@ -2644,7 +2680,7 @@ CALL [1] { } } result: { - IDENT [43] { + IDENT [45] { name: @ac:0:0 } } @@ -2838,82 +2874,79 @@ CALL [1] { } } } - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @ac:1:0 - } - IDENT [16] { - name: @index3 - } - } - } - LIST [17] { + LIST [14] { elements: { - IDENT [18] { + IDENT [15] { name: @index2 } - IDENT [19] { + IDENT [16] { name: @index2 } } } } } - CALL [20] { + CALL [17] { function: _==_ args: { - COMPREHENSION [21] { + COMPREHENSION [18] { iter_var: @it:0:0 iter_range: { - IDENT [22] { + IDENT [19] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [23] { + LIST [20] { elements: { } } } loop_condition: { - CONSTANT [24] { value: true } + CONSTANT [21] { value: true } } loop_step: { - CALL [25] { + CALL [22] { function: _+_ args: { - IDENT [26] { + IDENT [23] { name: @ac:0:0 } - LIST [27] { + LIST [24] { elements: { - COMPREHENSION [28] { + COMPREHENSION [25] { iter_var: @it:1:0 iter_range: { - IDENT [29] { + IDENT [26] { name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [30] { + LIST [27] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [28] { value: true } } loop_step: { - IDENT [32] { - name: @index4 + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @ac:1:0 + } + IDENT [31] { + name: @index3 + } + } } } result: { - IDENT [33] { + IDENT [32] { name: @ac:1:0 } } @@ -2924,13 +2957,13 @@ CALL [1] { } } result: { - IDENT [34] { + IDENT [33] { name: @ac:0:0 } } } - IDENT [35] { - name: @index5 + IDENT [34] { + name: @index4 } } } @@ -2981,59 +3014,30 @@ CALL [1] { } } } - CALL [15] { - function: _-_ - args: { - IDENT [16] { - name: @it:0:0 - } - CONSTANT [17] { value: 1 } - } - } - CALL [18] { - function: _>_ - args: { - IDENT [19] { - name: @index4 - } - CONSTANT [20] { value: 3 } - } - } - CALL [21] { - function: _||_ - args: { - IDENT [22] { - name: @ac:0:0 - } - IDENT [23] { - name: @index5 - } - } - } } } - CALL [24] { + CALL [15] { function: _||_ args: { - COMPREHENSION [25] { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - IDENT [26] { + IDENT [17] { name: @index3 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [27] { value: false } + CONSTANT [18] { value: false } } loop_condition: { - CALL [28] { + CALL [19] { function: @not_strictly_false args: { - CALL [29] { + CALL [20] { function: !_ args: { - IDENT [30] { + IDENT [21] { name: @ac:0:0 } } @@ -3042,17 +3046,37 @@ CALL [1] { } } loop_step: { - IDENT [31] { - name: @index6 + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @ac:0:0 + } + CALL [24] { + function: _>_ + args: { + CALL [25] { + function: _-_ + args: { + IDENT [26] { + name: @it:0:0 + } + CONSTANT [27] { value: 1 } + } + } + CONSTANT [28] { value: 3 } + } + } + } } } result: { - IDENT [32] { + IDENT [29] { name: @ac:0:0 } } } - IDENT [33] { + IDENT [30] { name: @index1 } } @@ -3067,119 +3091,76 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } - } - } - LIST [9] { - elements: { - CONSTANT [10] { value: "foo" } - CONSTANT [11] { value: "bar" } - } - } - LIST [12] { - elements: { - IDENT [13] { - name: @index0 - } - IDENT [14] { - name: @index0 - } - } - } - LIST [15] { - elements: { - IDENT [16] { - name: @index3 - } - } - } - CALL [17] { - function: _+_ - args: { - IDENT [18] { - name: @ac:1:0 - } - IDENT [19] { - name: @index4 - } - } - } - LIST [20] { - elements: { - IDENT [21] { - name: @index1 - } - IDENT [22] { - name: @index1 - } - } - } - LIST [23] { + LIST [3] { elements: { - IDENT [24] { - name: @index6 - } - } - } - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - IDENT [27] { - name: @index7 - } + CONSTANT [4] { value: "foo" } + CONSTANT [5] { value: "bar" } } } } } - COMPREHENSION [28] { + COMPREHENSION [6] { iter_var: @it:0:0 iter_range: { - COMPREHENSION [29] { + COMPREHENSION [7] { iter_var: @it:1:0 iter_range: { - IDENT [30] { - name: @index2 + IDENT [8] { + name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [31] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [32] { value: true } + CONSTANT [10] { value: true } } loop_step: { - IDENT [33] { - name: @index5 + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @ac:1:0 + } + LIST [13] { + elements: { + LIST [14] { + elements: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @it:1:0 + } + IDENT [17] { + name: @it:1:0 + } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @it:1:0 + } + IDENT [20] { + name: @it:1:0 + } + } + } + } + } + } + } + } } } result: { - IDENT [34] { + IDENT [21] { name: @ac:1:0 } } @@ -3187,21 +3168,56 @@ CALL [1] { } accu_var: @ac:0:0 accu_init: { - LIST [35] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [36] { value: true } + CONSTANT [23] { value: true } } loop_step: { - IDENT [37] { - name: @index8 + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @ac:0:0 + } + LIST [26] { + elements: { + LIST [27] { + elements: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @it:0:0 + } + IDENT [30] { + name: @it:0:0 + } + } + } + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @it:0:0 + } + IDENT [33] { + name: @it:0:0 + } + } + } + } + } + } + } + } } } result: { - IDENT [38] { + IDENT [34] { 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 28336f2e3..285b6183c 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,88 +1252,54 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _||_ - args: { - IDENT [4] { - name: @ac:0:0 - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:0 - } - CALL [10] { - function: _>_ - args: { - IDENT [11] { - name: @it:0:0 - } - CONSTANT [12] { value: 1 } - } - } - } - } - LIST [13] { + LIST [3] { elements: { - CONSTANT [14] { value: 1 } + CONSTANT [4] { value: 1 } } } - LIST [15] { + LIST [5] { elements: { - CONSTANT [16] { value: 2 } + CONSTANT [6] { value: 2 } } } } } - CALL [17] { + CALL [7] { function: _==_ args: { - CALL [18] { + CALL [8] { function: _+_ args: { - CALL [19] { + CALL [9] { function: _+_ args: { - CALL [20] { + CALL [10] { function: _+_ args: { - CALL [21] { + CALL [11] { function: size args: { - LIST [22] { + LIST [12] { elements: { - COMPREHENSION [23] { + COMPREHENSION [13] { iter_var: @it:0:0 iter_range: { - IDENT [24] { - name: @index2 + IDENT [14] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [25] { value: false } + CONSTANT [15] { value: false } } loop_condition: { - CALL [26] { + CALL [16] { function: @not_strictly_false args: { - CALL [27] { + CALL [17] { function: !_ args: { - IDENT [28] { + IDENT [18] { name: @ac:0:0 } } @@ -1342,12 +1308,26 @@ CALL [1] { } } loop_step: { - IDENT [29] { - name: @index0 + CALL [19] { + function: _||_ + args: { + IDENT [20] { + name: @ac:0:0 + } + CALL [21] { + function: _>_ + args: { + IDENT [22] { + name: @it:0:0 + } + CONSTANT [23] { value: 0 } + } + } + } } } result: { - IDENT [30] { + IDENT [24] { name: @ac:0:0 } } @@ -1356,30 +1336,30 @@ CALL [1] { } } } - CALL [31] { + CALL [25] { function: size args: { - LIST [32] { + LIST [26] { elements: { - COMPREHENSION [33] { + COMPREHENSION [27] { iter_var: @it:0:0 iter_range: { - IDENT [34] { - name: @index2 + IDENT [28] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [35] { value: false } + CONSTANT [29] { value: false } } loop_condition: { - CALL [36] { + CALL [30] { function: @not_strictly_false args: { - CALL [37] { + CALL [31] { function: !_ args: { - IDENT [38] { + IDENT [32] { name: @ac:0:0 } } @@ -1388,12 +1368,26 @@ CALL [1] { } } loop_step: { - IDENT [39] { - name: @index0 + CALL [33] { + function: _||_ + args: { + IDENT [34] { + name: @ac:0:0 + } + CALL [35] { + function: _>_ + args: { + IDENT [36] { + name: @it:0:0 + } + CONSTANT [37] { value: 0 } + } + } + } } } result: { - IDENT [40] { + IDENT [38] { name: @ac:0:0 } } @@ -1404,30 +1398,30 @@ CALL [1] { } } } - CALL [41] { + CALL [39] { function: size args: { - LIST [42] { + LIST [40] { elements: { - COMPREHENSION [43] { + COMPREHENSION [41] { iter_var: @it:0:0 iter_range: { - IDENT [44] { - name: @index3 + IDENT [42] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [45] { value: false } + CONSTANT [43] { value: false } } loop_condition: { - CALL [46] { + CALL [44] { function: @not_strictly_false args: { - CALL [47] { + CALL [45] { function: !_ args: { - IDENT [48] { + IDENT [46] { name: @ac:0:0 } } @@ -1436,12 +1430,26 @@ CALL [1] { } } loop_step: { - IDENT [49] { - name: @index1 + CALL [47] { + function: _||_ + args: { + IDENT [48] { + name: @ac:0:0 + } + CALL [49] { + function: _>_ + args: { + IDENT [50] { + name: @it:0:0 + } + CONSTANT [51] { value: 1 } + } + } + } } } result: { - IDENT [50] { + IDENT [52] { name: @ac:0:0 } } @@ -1452,30 +1460,30 @@ CALL [1] { } } } - CALL [51] { + CALL [53] { function: size args: { - LIST [52] { + LIST [54] { elements: { - COMPREHENSION [53] { + COMPREHENSION [55] { iter_var: @it:0:0 iter_range: { - IDENT [54] { - name: @index3 + IDENT [56] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [55] { value: false } + CONSTANT [57] { value: false } } loop_condition: { - CALL [56] { + CALL [58] { function: @not_strictly_false args: { - CALL [57] { + CALL [59] { function: !_ args: { - IDENT [58] { + IDENT [60] { name: @ac:0:0 } } @@ -1484,12 +1492,26 @@ CALL [1] { } } loop_step: { - IDENT [59] { - name: @index1 + CALL [61] { + function: _||_ + args: { + IDENT [62] { + name: @ac:0:0 + } + CALL [63] { + function: _>_ + args: { + IDENT [64] { + name: @it:0:0 + } + CONSTANT [65] { value: 1 } + } + } + } } } result: { - IDENT [60] { + IDENT [66] { name: @ac:0:0 } } @@ -1500,7 +1522,7 @@ CALL [1] { } } } - CONSTANT [61] { value: 4 } + CONSTANT [67] { value: 4 } } } } @@ -1513,93 +1535,59 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _||_ - args: { - IDENT [4] { - name: @ac:0:0 - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:1 - } - CALL [10] { - function: _==_ - args: { - IDENT [11] { - name: @it:0:1 - } - CONSTANT [12] { value: "a" } - } - } - } - } - LIST [13] { + LIST [3] { elements: { - CONSTANT [14] { value: 1 } + CONSTANT [4] { value: 1 } } } - LIST [15] { + LIST [5] { elements: { - CONSTANT [16] { value: "a" } + CONSTANT [6] { value: "a" } } } - LIST [17] { + LIST [7] { elements: { - CONSTANT [18] { value: true } - CONSTANT [19] { value: true } - CONSTANT [20] { value: true } - CONSTANT [21] { value: true } + CONSTANT [8] { value: true } + CONSTANT [9] { value: true } + CONSTANT [10] { value: true } + CONSTANT [11] { value: true } } } } } - CALL [22] { + CALL [12] { function: _==_ args: { - CALL [23] { + CALL [13] { function: _+_ args: { - CALL [24] { + CALL [14] { function: _+_ args: { - CALL [25] { + CALL [15] { function: _+_ args: { - LIST [26] { + LIST [16] { elements: { - COMPREHENSION [27] { + COMPREHENSION [17] { iter_var: @it:0:0 iter_range: { - IDENT [28] { - name: @index2 + IDENT [18] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [30] { + CALL [20] { function: @not_strictly_false args: { - CALL [31] { + CALL [21] { function: !_ args: { - IDENT [32] { + IDENT [22] { name: @ac:0:0 } } @@ -1608,39 +1596,53 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index0 + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 + } + CONSTANT [27] { value: 0 } + } + } + } } } result: { - IDENT [34] { + IDENT [28] { name: @ac:0:0 } } } } } - LIST [35] { + LIST [29] { elements: { - COMPREHENSION [36] { + COMPREHENSION [30] { iter_var: @it:0:0 iter_range: { - IDENT [37] { - name: @index2 + IDENT [31] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [32] { value: false } } loop_condition: { - CALL [39] { + CALL [33] { function: @not_strictly_false args: { - CALL [40] { + CALL [34] { function: !_ args: { - IDENT [41] { + IDENT [35] { name: @ac:0:0 } } @@ -1649,12 +1651,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index0 + CALL [36] { + function: _||_ + args: { + IDENT [37] { + name: @ac:0:0 + } + CALL [38] { + function: _>_ + args: { + IDENT [39] { + name: @it:0:0 + } + CONSTANT [40] { value: 0 } + } + } + } } } result: { - IDENT [43] { + IDENT [41] { name: @ac:0:0 } } @@ -1663,27 +1679,27 @@ CALL [1] { } } } - LIST [44] { + LIST [42] { elements: { - COMPREHENSION [45] { + COMPREHENSION [43] { iter_var: @it:0:1 iter_range: { - IDENT [46] { - name: @index3 + IDENT [44] { + name: @index1 } } accu_var: @ac:0:1 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: @ac:0:1 } } @@ -1692,12 +1708,26 @@ CALL [1] { } } loop_step: { - IDENT [51] { - name: @index1 + CALL [49] { + function: _||_ + args: { + IDENT [50] { + name: @ac:0:1 + } + CALL [51] { + function: _==_ + args: { + IDENT [52] { + name: @it:0:1 + } + CONSTANT [53] { value: "a" } + } + } + } } } result: { - IDENT [52] { + IDENT [54] { name: @ac:0:1 } } @@ -1706,27 +1736,27 @@ CALL [1] { } } } - LIST [53] { + LIST [55] { elements: { - COMPREHENSION [54] { + COMPREHENSION [56] { iter_var: @it:0:1 iter_range: { - IDENT [55] { - name: @index3 + IDENT [57] { + name: @index1 } } accu_var: @ac:0:1 accu_init: { - CONSTANT [56] { value: false } + CONSTANT [58] { value: false } } loop_condition: { - CALL [57] { + CALL [59] { function: @not_strictly_false args: { - CALL [58] { + CALL [60] { function: !_ args: { - IDENT [59] { + IDENT [61] { name: @ac:0:1 } } @@ -1735,12 +1765,26 @@ CALL [1] { } } loop_step: { - IDENT [60] { - name: @index1 + CALL [62] { + function: _||_ + args: { + IDENT [63] { + name: @ac:0:1 + } + CALL [64] { + function: _==_ + args: { + IDENT [65] { + name: @it:0:1 + } + CONSTANT [66] { value: "a" } + } + } + } } } result: { - IDENT [61] { + IDENT [67] { name: @ac:0:1 } } @@ -1749,8 +1793,8 @@ CALL [1] { } } } - IDENT [62] { - name: @index4 + IDENT [68] { + name: @index2 } } } @@ -1764,77 +1808,43 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _||_ - args: { - IDENT [4] { - name: @ac:0:0 - } - CALL [5] { - function: _>_ - args: { - IDENT [6] { - name: @it:0:0 - } - CONSTANT [7] { value: 0 } - } - } - } - } - CALL [8] { - function: _||_ - args: { - IDENT [9] { - name: @ac:0:0 - } - CALL [10] { - function: _>_ - args: { - IDENT [11] { - name: @it:0:0 - } - CONSTANT [12] { value: 1 } - } - } - } - } - LIST [13] { + LIST [3] { elements: { - CONSTANT [14] { value: 1 } + CONSTANT [4] { value: 1 } } } - LIST [15] { + LIST [5] { elements: { - CONSTANT [16] { value: 2 } + CONSTANT [6] { value: 2 } } } } } - CALL [17] { + CALL [7] { function: _&&_ args: { - CALL [18] { + CALL [8] { function: _&&_ args: { - COMPREHENSION [19] { + COMPREHENSION [9] { iter_var: @it:0:0 iter_range: { - IDENT [20] { - name: @index2 + IDENT [10] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [21] { value: false } + CONSTANT [11] { value: false } } loop_condition: { - CALL [22] { + CALL [12] { function: @not_strictly_false args: { - CALL [23] { + CALL [13] { function: !_ args: { - IDENT [24] { + IDENT [14] { name: @ac:0:0 } } @@ -1843,35 +1853,49 @@ CALL [1] { } } loop_step: { - IDENT [25] { - name: @index0 + CALL [15] { + function: _||_ + args: { + IDENT [16] { + name: @ac:0:0 + } + CALL [17] { + function: _>_ + args: { + IDENT [18] { + name: @it:0:0 + } + CONSTANT [19] { value: 0 } + } + } + } } } result: { - IDENT [26] { + IDENT [20] { name: @ac:0:0 } } } - COMPREHENSION [27] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - IDENT [28] { - name: @index2 + IDENT [22] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [23] { value: false } } loop_condition: { - CALL [30] { + CALL [24] { function: @not_strictly_false args: { - CALL [31] { + CALL [25] { function: !_ args: { - IDENT [32] { + IDENT [26] { name: @ac:0:0 } } @@ -1880,40 +1904,54 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index0 + CALL [27] { + function: _||_ + args: { + IDENT [28] { + name: @ac:0:0 + } + CALL [29] { + function: _>_ + args: { + IDENT [30] { + name: @it:0:0 + } + CONSTANT [31] { value: 0 } + } + } + } } } result: { - IDENT [34] { + IDENT [32] { name: @ac:0:0 } } } } } - CALL [35] { + CALL [33] { function: _&&_ args: { - COMPREHENSION [36] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - IDENT [37] { - name: @index2 + IDENT [35] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [36] { value: false } } loop_condition: { - CALL [39] { + CALL [37] { function: @not_strictly_false args: { - CALL [40] { + CALL [38] { function: !_ args: { - IDENT [41] { + IDENT [39] { name: @ac:0:0 } } @@ -1922,35 +1960,49 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 - } - } - result: { - IDENT [43] { - name: @ac:0:0 - } + CALL [40] { + function: _||_ + args: { + IDENT [41] { + name: @ac:0:0 + } + CALL [42] { + function: _>_ + args: { + IDENT [43] { + name: @it:0:0 + } + CONSTANT [44] { value: 1 } + } + } + } + } + } + result: { + IDENT [45] { + name: @ac:0:0 + } } } - COMPREHENSION [44] { + COMPREHENSION [46] { iter_var: @it:0:0 iter_range: { - IDENT [45] { - name: @index3 + IDENT [47] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [46] { value: false } + CONSTANT [48] { value: false } } loop_condition: { - CALL [47] { + CALL [49] { function: @not_strictly_false args: { - CALL [48] { + CALL [50] { function: !_ args: { - IDENT [49] { + IDENT [51] { name: @ac:0:0 } } @@ -1959,12 +2011,26 @@ CALL [1] { } } loop_step: { - IDENT [50] { - name: @index1 + CALL [52] { + function: _||_ + args: { + IDENT [53] { + name: @ac:0:0 + } + CALL [54] { + function: _>_ + args: { + IDENT [55] { + name: @it:0:0 + } + CONSTANT [56] { value: 1 } + } + } + } } } result: { - IDENT [51] { + IDENT [57] { name: @ac:0:0 } } @@ -1999,116 +2065,107 @@ CALL [1] { } LIST [11] { elements: { - CALL [12] { - function: _+_ - args: { - IDENT [13] { - name: @it:1:0 - } - CONSTANT [14] { value: 1 } - } + IDENT [12] { + name: @index1 + } + IDENT [13] { + name: @index1 + } + IDENT [14] { + name: @index1 } } } - COMPREHENSION [15] { - iter_var: @it:1:0 + } + } + CALL [15] { + function: _==_ + args: { + COMPREHENSION [16] { + iter_var: @it:0:0 iter_range: { - IDENT [16] { + IDENT [17] { name: @index0 } } - accu_var: @ac:1:0 + accu_var: @ac:0:0 accu_init: { - LIST [17] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [19] { + CALL [20] { function: _+_ args: { - IDENT [20] { - name: @ac:1:0 - } IDENT [21] { - name: @index2 + name: @ac:0:0 } - } - } - } - result: { - IDENT [22] { - name: @ac:1:0 - } - } - } - CALL [23] { - function: _+_ - args: { - IDENT [24] { - name: @ac:0:0 - } - LIST [25] { - elements: { - IDENT [26] { - name: @index3 + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @it:1:0 + iter_range: { + IDENT [24] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @ac:1:0 + } + LIST [29] { + elements: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @it:1:0 + } + CONSTANT [32] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [33] { + name: @ac:1:0 + } + } + } + } } } } } - } - COMPREHENSION [27] { - iter_var: @it:0:0 - iter_range: { - IDENT [28] { - name: @index0 - } - } - accu_var: @ac:0:0 - accu_init: { - LIST [29] { - elements: { - } - } - } - loop_condition: { - CONSTANT [30] { value: true } - } - loop_step: { - IDENT [31] { - name: @index4 - } - } result: { - IDENT [32] { + IDENT [34] { name: @ac:0:0 } } } - } - } - CALL [33] { - function: _==_ - args: { - IDENT [34] { - name: @index5 - } - LIST [35] { - elements: { - IDENT [36] { - name: @index1 - } - IDENT [37] { - name: @index1 - } - IDENT [38] { - name: @index1 - } - } + IDENT [35] { + name: @index2 } } } @@ -2122,145 +2179,136 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @ac:1:0 - } - LIST [5] { - elements: { - IDENT [6] { - name: @it:1:0 - } - } - } - } - } - CALL [7] { - function: _?_:_ - args: { - CALL [8] { - function: _==_ - args: { - IDENT [9] { - name: @it:1:0 - } - IDENT [10] { - name: @it:0:0 - } - } - } - IDENT [11] { - name: @index0 - } - IDENT [12] { - name: @ac:1:0 - } - } - } - COMPREHENSION [13] { - iter_var: @it:1:0 - iter_range: { - LIST [14] { + LIST [3] { + elements: { + LIST [4] { elements: { - CONSTANT [15] { value: 1 } - CONSTANT [16] { value: 2 } - CONSTANT [17] { value: 3 } + CONSTANT [5] { value: 1 } } } - } - accu_var: @ac:1:0 - accu_init: { - LIST [18] { + LIST [6] { elements: { + CONSTANT [7] { value: 2 } } } } - loop_condition: { - CONSTANT [19] { value: true } - } - loop_step: { - IDENT [20] { - name: @index1 - } - } - result: { - IDENT [21] { - name: @ac:1:0 - } + } + LIST [8] { + elements: { + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } } } - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @ac:0:0 - } - LIST [24] { - elements: { - IDENT [25] { - name: @index2 - } - } - } + LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } } } - COMPREHENSION [26] { + } + } + CALL [15] { + function: _==_ + args: { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - LIST [27] { - elements: { - CONSTANT [28] { value: 1 } - CONSTANT [29] { value: 2 } - } + IDENT [17] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [30] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [19] { value: true } } loop_step: { - IDENT [32] { - name: @index3 + CALL [20] { + function: _+_ + args: { + IDENT [21] { + name: @ac:0:0 + } + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @it:1:0 + iter_range: { + IDENT [24] { + name: @index2 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + CALL [27] { + function: _?_:_ + args: { + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @it:1:0 + } + IDENT [30] { + name: @it:0:0 + } + } + } + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @ac:1:0 + } + LIST [33] { + elements: { + IDENT [34] { + name: @it:1:0 + } + } + } + } + } + IDENT [35] { + name: @ac:1:0 + } + } + } + } + result: { + IDENT [36] { + name: @ac:1:0 + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [37] { name: @ac:0:0 } } } - LIST [34] { - elements: { - LIST [35] { - elements: { - CONSTANT [36] { value: 1 } - } - } - LIST [37] { - elements: { - CONSTANT [38] { value: 2 } - } - } - } - } - } - } - CALL [39] { - function: _==_ - args: { - IDENT [40] { - name: @index4 - } - IDENT [41] { - name: @index5 + IDENT [38] { + name: @index0 } } } @@ -2276,117 +2324,184 @@ CALL [1] { elements: { LIST [3] { elements: { - CALL [4] { - function: _+_ - args: { - IDENT [5] { - name: @it:1:0 - } - CONSTANT [6] { value: 1 } - } - } + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } } } - COMPREHENSION [7] { - iter_var: @it:1:0 + } + } + CALL [7] { + function: _==_ + args: { + COMPREHENSION [8] { + iter_var: @it:0:0 iter_range: { - LIST [8] { - elements: { - CONSTANT [9] { value: 1 } - CONSTANT [10] { value: 2 } - CONSTANT [11] { value: 3 } - } + IDENT [9] { + name: @index0 } } - accu_var: @ac:1:0 + accu_var: @ac:0:0 accu_init: { - LIST [12] { + LIST [10] { elements: { } } } loop_condition: { - CONSTANT [13] { value: true } + CONSTANT [11] { value: true } } loop_step: { - CALL [14] { + CALL [12] { function: _+_ args: { - IDENT [15] { - name: @ac:1:0 + IDENT [13] { + name: @ac:0:0 } - IDENT [16] { - name: @index0 + LIST [14] { + elements: { + COMPREHENSION [15] { + iter_var: @it:1:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @ac:1:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @it:1:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @ac:1:0 + } + } + } + } } - } - } - } - result: { - IDENT [17] { - name: @ac:1:0 + } } } - } - CALL [18] { - function: _+_ - args: { - IDENT [19] { + result: { + IDENT [26] { name: @ac:0:0 } - LIST [20] { - elements: { - IDENT [21] { - name: @index1 - } - } - } } } - COMPREHENSION [22] { + COMPREHENSION [27] { iter_var: @it:0:0 iter_range: { - LIST [23] { - elements: { - CONSTANT [24] { value: 1 } - CONSTANT [25] { value: 2 } - CONSTANT [26] { value: 3 } - } + IDENT [28] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [27] { + LIST [29] { elements: { } } } loop_condition: { - CONSTANT [28] { value: true } + CONSTANT [30] { value: true } } loop_step: { - IDENT [29] { - name: @index2 + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @ac:0:0 + } + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @it:1:0 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @ac:1:0 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @it:1:0 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @ac:1:0 + } + } + } + } + } + } } } result: { - IDENT [30] { + IDENT [45] { name: @ac:0:0 } } } } } - CALL [31] { - function: _==_ - args: { - IDENT [32] { - name: @index3 - } - IDENT [33] { - name: @index3 - } - } - } } } Test case: INCLUSION_LIST @@ -2605,63 +2720,60 @@ CALL [1] { } } } - CALL [25] { - function: _+_ - args: { + LIST [25] { + elements: { IDENT [26] { - name: @ac:0:0 - } - LIST [27] { - elements: { - IDENT [28] { - name: @index3 - } - } + name: @index3 } } } - COMPREHENSION [29] { + } + } + CALL [27] { + function: _==_ + args: { + COMPREHENSION [28] { iter_var: @it:0:0 iter_range: { - IDENT [30] { + IDENT [29] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [31] { + LIST [30] { elements: { } } } loop_condition: { - CONSTANT [32] { value: true } + CONSTANT [31] { value: true } } loop_step: { - IDENT [33] { - name: @index4 + CALL [32] { + function: _+_ + args: { + IDENT [33] { + name: @ac:0:0 + } + IDENT [34] { + name: @index4 + } + } } } result: { - IDENT [34] { + IDENT [35] { name: @ac:0:0 } } } - } - } - CALL [35] { - function: _==_ - args: { - IDENT [36] { - name: @index5 - } - LIST [37] { + LIST [36] { elements: { - IDENT [38] { + IDENT [37] { name: @index0 } - IDENT [39] { + IDENT [38] { name: @index0 } } @@ -2711,63 +2823,37 @@ CALL [1] { CONSTANT [13] { value: 5 } } } - CALL [14] { - function: _>_ - args: { - CALL [15] { - function: _-_ - args: { - IDENT [16] { - name: @it:0:0 - } - CONSTANT [17] { value: 1 } - } - } - CONSTANT [18] { value: 3 } - } - } - LIST [19] { + LIST [14] { elements: { - IDENT [20] { + IDENT [15] { name: @index1 } } } - CALL [21] { - function: _||_ - args: { - IDENT [22] { - name: @ac:0:0 - } - IDENT [23] { - name: @index2 - } - } - } } } - CALL [24] { + CALL [16] { function: _||_ args: { - COMPREHENSION [25] { + COMPREHENSION [17] { iter_var: @it:0:0 iter_range: { - IDENT [26] { - name: @index3 + IDENT [18] { + name: @index2 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [27] { value: false } + CONSTANT [19] { value: false } } loop_condition: { - CALL [28] { + CALL [20] { function: @not_strictly_false args: { - CALL [29] { + CALL [21] { function: !_ args: { - IDENT [30] { + IDENT [22] { name: @ac:0:0 } } @@ -2776,17 +2862,37 @@ CALL [1] { } } loop_step: { - IDENT [31] { - name: @index4 + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + CALL [26] { + function: _-_ + args: { + IDENT [27] { + name: @it:0:0 + } + CONSTANT [28] { value: 1 } + } + } + CONSTANT [29] { value: 3 } + } + } + } } } result: { - IDENT [32] { + IDENT [30] { name: @ac:0:0 } } } - IDENT [33] { + IDENT [31] { name: @index0 } } @@ -2801,123 +2907,127 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } - } - } - LIST [9] { + LIST [3] { elements: { - LIST [10] { - elements: { - IDENT [11] { - name: @index0 - } - IDENT [12] { - name: @index0 - } - } - } + CONSTANT [4] { value: "foo" } + CONSTANT [5] { value: "bar" } } } - COMPREHENSION [13] { + } + } + COMPREHENSION [6] { + iter_var: @it:0:0 + iter_range: { + COMPREHENSION [7] { iter_var: @it:1:0 iter_range: { - LIST [14] { - elements: { - CONSTANT [15] { value: "foo" } - CONSTANT [16] { value: "bar" } - } + IDENT [8] { + name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [17] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [10] { value: true } } loop_step: { - CALL [19] { + CALL [11] { function: _+_ args: { - IDENT [20] { + IDENT [12] { name: @ac:1:0 } - IDENT [21] { - name: @index2 + LIST [13] { + elements: { + LIST [14] { + elements: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @it:1:0 + } + IDENT [17] { + name: @it:1:0 + } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @it:1:0 + } + IDENT [20] { + name: @it:1:0 + } + } + } + } + } + } } } } } result: { - IDENT [22] { + IDENT [21] { name: @ac:1:0 } } } - LIST [23] { - elements: { - LIST [24] { - elements: { - IDENT [25] { - name: @index1 - } - IDENT [26] { - name: @index1 - } - } - } - } - } - } - } - COMPREHENSION [27] { - iter_var: @it:0:0 - iter_range: { - IDENT [28] { - name: @index3 - } } accu_var: @ac:0:0 accu_init: { - LIST [29] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [23] { value: true } } loop_step: { - CALL [31] { + CALL [24] { function: _+_ args: { - IDENT [32] { + IDENT [25] { name: @ac:0:0 } - IDENT [33] { - name: @index4 + LIST [26] { + elements: { + LIST [27] { + elements: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @it:0:0 + } + IDENT [30] { + name: @it:0:0 + } + } + } + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @it:0:0 + } + IDENT [33] { + name: @it: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 4018942c4..d9211978c 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 @@ -1605,125 +1605,130 @@ CALL [1] { } } } - CALL [16] { - function: _||_ + } + } + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: _&&_ args: { - IDENT [17] { - name: @ac:0:0 + IDENT [18] { + name: @index0 } - CALL [18] { - function: _>_ - args: { - IDENT [19] { - name: @it:0:0 - } - CONSTANT [20] { value: 1 } - } + IDENT [19] { + name: @index0 } } } - COMPREHENSION [21] { - iter_var: @it:0:0 - iter_range: { - LIST [22] { - elements: { - CONSTANT [23] { value: 1 } + 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: !_ + accu_var: @ac:0:0 + accu_init: { + CONSTANT [24] { value: false } + } + loop_condition: { + CALL [25] { + function: @not_strictly_false args: { - IDENT [27] { + 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 } + } + } } } } - } - } - loop_step: { - IDENT [28] { - name: @index1 - } - } - result: { - IDENT [29] { - name: @ac:0:0 - } - } - } - COMPREHENSION [30] { - iter_var: @it:0:0 - iter_range: { - LIST [31] { - elements: { - CONSTANT [32] { value: 2 } + result: { + IDENT [33] { + name: @ac:0:0 + } } } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [33] { value: false } - } - loop_condition: { - CALL [34] { - function: @not_strictly_false - args: { - CALL [35] { - function: !_ + 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: { - IDENT [36] { + 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 } + } + } } } } - } - } - loop_step: { - IDENT [37] { - name: @index1 - } - } - result: { - IDENT [38] { - name: @ac:0:0 - } - } - } - } - } - CALL [39] { - function: _&&_ - args: { - CALL [40] { - function: _&&_ - args: { - IDENT [41] { - name: @index0 - } - IDENT [42] { - name: @index0 - } - } - } - CALL [43] { - function: _&&_ - args: { - IDENT [44] { - name: @index2 - } - IDENT [45] { - name: @index3 + result: { + IDENT [46] { + name: @ac:0:0 + } + } } } } @@ -1753,112 +1758,109 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CALL [11] { - function: _+_ - args: { + LIST [11] { + elements: { IDENT [12] { - name: @ac:1:0 + name: @index1 } - LIST [13] { - elements: { - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @it:1:0 - } - CONSTANT [16] { value: 1 } - } - } - } + IDENT [13] { + name: @index1 } - } - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @it:1:0 - iter_range: { - IDENT [19] { - name: @index0 - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [20] { - elements: { - } - } - } - loop_condition: { - CONSTANT [21] { value: true } - } - loop_step: { - IDENT [22] { - name: @index2 - } - } - result: { - IDENT [23] { - name: @ac:1:0 - } - } + IDENT [14] { + name: @index1 } } } } } - CALL [24] { + CALL [15] { function: _==_ args: { - COMPREHENSION [25] { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - IDENT [26] { + IDENT [17] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [27] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [28] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [29] { + CALL [20] { function: _+_ args: { - IDENT [30] { + IDENT [21] { name: @ac:0:0 } - IDENT [31] { - name: @index3 + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @it:1:0 + iter_range: { + IDENT [24] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @ac:1:0 + } + LIST [29] { + elements: { + CALL [30] { + function: _+_ + args: { + IDENT [31] { + name: @it:1:0 + } + CONSTANT [32] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [33] { + name: @ac:1:0 + } + } + } + } } } } } result: { - IDENT [32] { + IDENT [34] { name: @ac:0:0 } } } - LIST [33] { - elements: { - IDENT [34] { - name: @index1 - } - IDENT [35] { - name: @index1 - } - IDENT [36] { - name: @index1 - } - } + IDENT [35] { + name: @index2 } } } @@ -1872,133 +1874,136 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _?_:_ - args: { - CALL [4] { - function: _==_ - args: { - IDENT [5] { - name: @it:1:0 - } - IDENT [6] { - name: @it:0:0 - } + LIST [3] { + elements: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } } - CALL [7] { - function: _+_ - args: { - IDENT [8] { - name: @ac:1:0 - } - LIST [9] { - elements: { - IDENT [10] { - name: @it:1:0 - } - } - } + LIST [6] { + elements: { + CONSTANT [7] { value: 2 } } } - IDENT [11] { - name: @ac:1:0 - } } } - LIST [12] { + LIST [8] { elements: { - COMPREHENSION [13] { - iter_var: @it:1:0 - iter_range: { - LIST [14] { - elements: { - CONSTANT [15] { value: 1 } - CONSTANT [16] { value: 2 } - CONSTANT [17] { value: 3 } - } - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [18] { - elements: { - } - } - } - loop_condition: { - CONSTANT [19] { value: true } - } - loop_step: { - IDENT [20] { - name: @index0 - } - } - result: { - IDENT [21] { - name: @ac:1:0 - } - } - } + CONSTANT [9] { value: 1 } + CONSTANT [10] { value: 2 } + } + } + LIST [11] { + elements: { + CONSTANT [12] { value: 1 } + CONSTANT [13] { value: 2 } + CONSTANT [14] { value: 3 } } } } } - CALL [22] { + CALL [15] { function: _==_ args: { - COMPREHENSION [23] { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - LIST [24] { - elements: { - CONSTANT [25] { value: 1 } - CONSTANT [26] { value: 2 } - } + IDENT [17] { + name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [27] { + LIST [18] { elements: { } } } loop_condition: { - CONSTANT [28] { value: true } + CONSTANT [19] { value: true } } loop_step: { - CALL [29] { + CALL [20] { function: _+_ args: { - IDENT [30] { + IDENT [21] { name: @ac:0:0 } - IDENT [31] { - name: @index1 + LIST [22] { + elements: { + COMPREHENSION [23] { + iter_var: @it:1:0 + iter_range: { + IDENT [24] { + name: @index2 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [25] { + elements: { + } + } + } + loop_condition: { + CONSTANT [26] { value: true } + } + loop_step: { + CALL [27] { + function: _?_:_ + args: { + CALL [28] { + function: _==_ + args: { + IDENT [29] { + name: @it:1:0 + } + IDENT [30] { + name: @it:0:0 + } + } + } + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @ac:1:0 + } + LIST [33] { + elements: { + IDENT [34] { + name: @it:1:0 + } + } + } + } + } + IDENT [35] { + name: @ac:1:0 + } + } + } + } + result: { + IDENT [36] { + name: @ac:1:0 + } + } + } + } } } } } result: { - IDENT [32] { + IDENT [37] { name: @ac:0:0 } } } - LIST [33] { - elements: { - LIST [34] { - elements: { - CONSTANT [35] { value: 1 } - } - } - LIST [36] { - elements: { - CONSTANT [37] { value: 2 } - } - } - } + IDENT [38] { + name: @index0 } } } @@ -2012,116 +2017,186 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @ac:1:0 + LIST [3] { + elements: { + CONSTANT [4] { value: 1 } + CONSTANT [5] { value: 2 } + CONSTANT [6] { value: 3 } + } + } + } + } + CALL [7] { + function: _==_ + args: { + COMPREHENSION [8] { + iter_var: @it:0:0 + iter_range: { + IDENT [9] { + name: @index0 } - LIST [5] { + } + accu_var: @ac:0:0 + accu_init: { + LIST [10] { elements: { - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:1:0 - } - CONSTANT [8] { value: 1 } - } - } } } } - } - LIST [9] { - elements: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: 1 } - CONSTANT [13] { value: 2 } - CONSTANT [14] { value: 3 } - } - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [15] { - elements: { - } - } - } - loop_condition: { - CONSTANT [16] { value: true } - } - loop_step: { - IDENT [17] { - name: @index0 - } - } - result: { - IDENT [18] { - name: @ac:1:0 + loop_condition: { + CONSTANT [11] { value: true } + } + loop_step: { + CALL [12] { + function: _+_ + args: { + IDENT [13] { + name: @ac:0:0 + } + LIST [14] { + elements: { + COMPREHENSION [15] { + iter_var: @it:1:0 + iter_range: { + IDENT [16] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [17] { + elements: { + } + } + } + loop_condition: { + CONSTANT [18] { value: true } + } + loop_step: { + CALL [19] { + function: _+_ + args: { + IDENT [20] { + name: @ac:1:0 + } + LIST [21] { + elements: { + CALL [22] { + function: _+_ + args: { + IDENT [23] { + name: @it:1:0 + } + CONSTANT [24] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [25] { + name: @ac:1:0 + } + } + } + } } } } } + result: { + IDENT [26] { + name: @ac:0:0 + } + } } - COMPREHENSION [19] { + COMPREHENSION [27] { iter_var: @it:0:0 iter_range: { - LIST [20] { - elements: { - CONSTANT [21] { value: 1 } - CONSTANT [22] { value: 2 } - CONSTANT [23] { value: 3 } - } + IDENT [28] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [24] { + LIST [29] { elements: { } } } loop_condition: { - CONSTANT [25] { value: true } + CONSTANT [30] { value: true } } loop_step: { - CALL [26] { + CALL [31] { function: _+_ args: { - IDENT [27] { + IDENT [32] { name: @ac:0:0 } - IDENT [28] { - name: @index1 + LIST [33] { + elements: { + COMPREHENSION [34] { + iter_var: @it:1:0 + iter_range: { + IDENT [35] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [36] { + elements: { + } + } + } + loop_condition: { + CONSTANT [37] { value: true } + } + loop_step: { + CALL [38] { + function: _+_ + args: { + IDENT [39] { + name: @ac:1:0 + } + LIST [40] { + elements: { + CALL [41] { + function: _+_ + args: { + IDENT [42] { + name: @it:1:0 + } + CONSTANT [43] { value: 1 } + } + } + } + } + } + } + } + result: { + IDENT [44] { + name: @ac:1:0 + } + } + } + } } } } } result: { - IDENT [29] { + IDENT [45] { name: @ac:0:0 } } } } } - CALL [30] { - function: _==_ - args: { - IDENT [31] { - name: @index2 - } - IDENT [32] { - name: @index2 - } - } - } } } Test case: INCLUSION_LIST @@ -2291,87 +2366,87 @@ CALL [1] { CONSTANT [12] { value: 2 } } } - CALL [13] { - function: _+_ - args: { - IDENT [14] { - name: @ac:1:0 - } - LIST [15] { + LIST [13] { + elements: { + LIST [14] { elements: { - LIST [16] { - elements: { - CONSTANT [17] { value: 3 } - CONSTANT [18] { value: 4 } - } - } + CONSTANT [15] { value: 3 } + CONSTANT [16] { value: 4 } } } } } - LIST [19] { - elements: { - COMPREHENSION [20] { - iter_var: @it:1:0 - iter_range: { - IDENT [21] { - name: @index1 - } + COMPREHENSION [17] { + iter_var: @it:1:0 + iter_range: { + IDENT [18] { + name: @index1 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [19] { + elements: { } - accu_var: @ac:1:0 - accu_init: { - LIST [22] { - elements: { - } + } + } + loop_condition: { + CONSTANT [20] { value: true } + } + loop_step: { + CALL [21] { + function: _+_ + args: { + IDENT [22] { + name: @ac:1:0 } - } - loop_condition: { - CONSTANT [23] { value: true } - } - loop_step: { - IDENT [24] { + IDENT [23] { name: @index2 } } - result: { - IDENT [25] { - name: @ac:1:0 - } - } + } + } + result: { + IDENT [24] { + name: @ac:1:0 } } } } } - CALL [26] { + CALL [25] { function: _==_ args: { - COMPREHENSION [27] { + COMPREHENSION [26] { iter_var: @it:0:0 iter_range: { - IDENT [28] { + IDENT [27] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [29] { + LIST [28] { elements: { } } } loop_condition: { - CONSTANT [30] { value: true } + CONSTANT [29] { value: true } } loop_step: { - CALL [31] { + CALL [30] { function: _+_ args: { - IDENT [32] { + IDENT [31] { name: @ac:0:0 } - IDENT [33] { - name: @index3 + LIST [32] { + elements: { + IDENT [33] { + name: @index3 + } + } } } } @@ -2441,48 +2516,30 @@ CALL [1] { } } } - CALL [15] { - function: _||_ - args: { - IDENT [16] { - name: @ac:0:0 - } - CALL [17] { - function: _>_ - args: { - CALL [18] { - function: _-_ - args: { - IDENT [19] { - name: @it:0:0 - } - CONSTANT [20] { value: 1 } - } - } - CONSTANT [21] { value: 3 } - } - } - } - } - COMPREHENSION [22] { + } + } + CALL [15] { + function: _||_ + args: { + COMPREHENSION [16] { iter_var: @it:0:0 iter_range: { - IDENT [23] { + IDENT [17] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - CONSTANT [24] { value: false } + CONSTANT [18] { value: false } } loop_condition: { - CALL [25] { + CALL [19] { function: @not_strictly_false args: { - CALL [26] { + CALL [20] { function: !_ args: { - IDENT [27] { + IDENT [21] { name: @ac:0:0 } } @@ -2491,8 +2548,28 @@ CALL [1] { } } loop_step: { - IDENT [28] { - name: @index2 + CALL [22] { + function: _||_ + args: { + IDENT [23] { + name: @ac:0:0 + } + CALL [24] { + function: _>_ + args: { + CALL [25] { + function: _-_ + args: { + IDENT [26] { + name: @it:0:0 + } + CONSTANT [27] { value: 1 } + } + } + CONSTANT [28] { value: 3 } + } + } + } } } result: { @@ -2501,15 +2578,7 @@ CALL [1] { } } } - } - } - CALL [30] { - function: _||_ - args: { - IDENT [31] { - name: @index3 - } - IDENT [32] { + IDENT [30] { name: @index0 } } @@ -2524,104 +2593,76 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } - } - } - CALL [9] { - function: _+_ - args: { - IDENT [10] { - name: @ac:1:0 - } - LIST [11] { - elements: { - LIST [12] { - elements: { - IDENT [13] { - name: @index0 - } - IDENT [14] { - name: @index0 - } - } - } - } - } - } - } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @ac:0:0 - } - LIST [17] { - elements: { - LIST [18] { - elements: { - IDENT [19] { - name: @index1 - } - IDENT [20] { - name: @index1 - } - } - } - } - } + LIST [3] { + elements: { + CONSTANT [4] { value: "foo" } + CONSTANT [5] { value: "bar" } } } } } - COMPREHENSION [21] { + COMPREHENSION [6] { iter_var: @it:0:0 iter_range: { - COMPREHENSION [22] { + COMPREHENSION [7] { iter_var: @it:1:0 iter_range: { - LIST [23] { - elements: { - CONSTANT [24] { value: "foo" } - CONSTANT [25] { value: "bar" } - } + IDENT [8] { + name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [26] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [10] { value: true } } loop_step: { - IDENT [28] { - name: @index2 + CALL [11] { + function: _+_ + args: { + IDENT [12] { + name: @ac:1:0 + } + LIST [13] { + elements: { + LIST [14] { + elements: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @it:1:0 + } + IDENT [17] { + name: @it:1:0 + } + } + } + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @it:1:0 + } + IDENT [20] { + name: @it:1:0 + } + } + } + } + } + } + } + } } } result: { - IDENT [29] { + IDENT [21] { name: @ac:1:0 } } @@ -2629,21 +2670,56 @@ CALL [1] { } accu_var: @ac:0:0 accu_init: { - LIST [30] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [23] { value: true } } loop_step: { - IDENT [32] { - name: @index3 + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @ac:0:0 + } + LIST [26] { + elements: { + LIST [27] { + elements: { + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @it:0:0 + } + IDENT [30] { + name: @it:0:0 + } + } + } + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @it:0:0 + } + IDENT [33] { + name: @it:0:0 + } + } + } + } + } + } + } + } } } result: { - IDENT [33] { + IDENT [34] { 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 69d2d6af5..cf40f26ee 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 @@ -1169,133 +1169,133 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @it:0:0 - iter_range: { - LIST [19] { - elements: { - CONSTANT [20] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [21] { value: false } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:0 - } - } + IDENT [22] { + name: @ac:0:0 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } CALL [25] { - function: _||_ + function: _>_ args: { IDENT [26] { - name: @ac:0:0 - } - CALL [27] { - function: _>_ - args: { - IDENT [28] { - name: @it:0:0 - } - CONSTANT [29] { value: 1 } - } + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } - result: { - IDENT [30] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:0 } } } - CALL [31] { + CALL [29] { function: size args: { - IDENT [32] { - name: @index0 + LIST [30] { + elements: { + IDENT [31] { + name: @index0 + } + } } } } - CALL [33] { + CALL [32] { function: size args: { - IDENT [34] { - name: @index1 + LIST [33] { + elements: { + IDENT [34] { + name: @index1 + } + } } } } @@ -1344,158 +1344,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1563,47 +1569,46 @@ CALL [1] { } } } - CALL [16] { - function: _||_ + } + } + CALL [16] { + function: _&&_ + args: { + CALL [17] { + function: _&&_ args: { - IDENT [17] { - name: @ac:0:0 + IDENT [18] { + name: @index0 } - CALL [18] { - function: _>_ - args: { - IDENT [19] { - name: @it:0:0 - } - CONSTANT [20] { value: 1 } - } + IDENT [19] { + name: @index0 } } } - CALL [21] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [22] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [23] { + LIST [22] { elements: { - CONSTANT [24] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [25] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [26] { + CALL [25] { function: @not_strictly_false args: { - CALL [27] { + CALL [26] { function: !_ args: { - IDENT [28] { + IDENT [27] { name: @ac:0:0 } } @@ -1612,37 +1617,51 @@ CALL [1] { } } loop_step: { - IDENT [29] { - name: @index1 + 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 [30] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [31] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [32] { + LIST [35] { elements: { - CONSTANT [33] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [34] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [35] { + CALL [38] { function: @not_strictly_false args: { - CALL [36] { + CALL [39] { function: !_ args: { - IDENT [37] { + IDENT [40] { name: @ac:0:0 } } @@ -1651,12 +1670,26 @@ CALL [1] { } } loop_step: { - IDENT [38] { - name: @index1 + 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 [39] { + IDENT [46] { name: @ac:0:0 } } @@ -1665,25 +1698,6 @@ CALL [1] { } } } - CALL [40] { - function: _&&_ - args: { - CALL [41] { - function: _&&_ - args: { - IDENT [42] { - name: @index0 - } - IDENT [43] { - name: @index0 - } - } - } - IDENT [44] { - name: @index2 - } - } - } } } Test case: NESTED_MACROS @@ -2359,27 +2373,32 @@ CALL [1] { CONSTANT [7] { value: 3 } } } - COMPREHENSION [8] { + } + } + CALL [8] { + function: _||_ + args: { + COMPREHENSION [9] { iter_var: @it:0:0 iter_range: { - LIST [9] { + LIST [10] { elements: { - CALL [10] { + CALL [11] { function: _?_:_ args: { - IDENT [11] { + IDENT [12] { name: @index0 } - CALL [12] { + CALL [13] { function: _-_ args: { - IDENT [13] { + IDENT [14] { name: x } - CONSTANT [14] { value: 1 } + CONSTANT [15] { value: 1 } } } - CONSTANT [15] { value: 5 } + CONSTANT [16] { value: 5 } } } } @@ -2387,16 +2406,16 @@ CALL [1] { } accu_var: @ac:0:0 accu_init: { - CONSTANT [16] { value: false } + CONSTANT [17] { value: false } } loop_condition: { - CALL [17] { + CALL [18] { function: @not_strictly_false args: { - CALL [18] { + CALL [19] { function: !_ args: { - IDENT [19] { + IDENT [20] { name: @ac:0:0 } } @@ -2405,45 +2424,37 @@ CALL [1] { } } loop_step: { - CALL [20] { + CALL [21] { function: _||_ args: { - IDENT [21] { + IDENT [22] { name: @ac:0:0 } - CALL [22] { + CALL [23] { function: _>_ args: { - CALL [23] { + CALL [24] { function: _-_ args: { - IDENT [24] { + IDENT [25] { name: @it:0:0 } - CONSTANT [25] { value: 1 } + CONSTANT [26] { value: 1 } } } - CONSTANT [26] { value: 3 } + CONSTANT [27] { value: 3 } } } } } } result: { - IDENT [27] { + IDENT [28] { name: @ac:0:0 } } } - } - } - CALL [28] { - function: _||_ - args: { IDENT [29] { - name: @index1 - } - IDENT [30] { name: @index0 } } @@ -2458,64 +2469,66 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + LIST [3] { + elements: { + CONSTANT [4] { value: "foo" } + CONSTANT [5] { value: "bar" } } } - COMPREHENSION [9] { + } + } + COMPREHENSION [6] { + iter_var: @it:0:0 + iter_range: { + COMPREHENSION [7] { iter_var: @it:1:0 iter_range: { - LIST [10] { - elements: { - CONSTANT [11] { value: "foo" } - CONSTANT [12] { value: "bar" } - } + IDENT [8] { + name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [13] { + LIST [9] { elements: { } } } loop_condition: { - CONSTANT [14] { value: true } + CONSTANT [10] { value: true } } loop_step: { - CALL [15] { + CALL [11] { function: _+_ args: { - IDENT [16] { + IDENT [12] { name: @ac:1:0 } - LIST [17] { + LIST [13] { elements: { - LIST [18] { + LIST [14] { elements: { - IDENT [19] { - name: @index0 + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @it:1:0 + } + IDENT [17] { + name: @it:1:0 + } + } } - IDENT [20] { - name: @index0 + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @it:1:0 + } + IDENT [20] { + name: @it:1:0 + } + } } } } @@ -2531,40 +2544,48 @@ CALL [1] { } } } - } - COMPREHENSION [22] { - iter_var: @it:0:0 - iter_range: { - IDENT [23] { - name: @index2 - } - } accu_var: @ac:0:0 accu_init: { - LIST [24] { + 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: @ac:0:0 } - LIST [28] { + LIST [26] { elements: { - LIST [29] { + LIST [27] { elements: { - IDENT [30] { - name: @index1 + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @it:0:0 + } + IDENT [30] { + name: @it:0:0 + } + } } - IDENT [31] { - name: @index1 + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @it:0:0 + } + IDENT [33] { + name: @it:0:0 + } + } } } } @@ -2574,7 +2595,7 @@ CALL [1] { } } result: { - IDENT [32] { + IDENT [34] { 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 e27f91a0d..0eadf7a83 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,125 +1151,131 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } + 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 } } - 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 [11] { - 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 } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ + args: { + IDENT [22] { + name: @ac:0:0 } } - result: { - IDENT [17] { - name: @ac:0:0 + } + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } } } + result: { + IDENT [28] { + name: @ac:0:0 + } + } } - CALL [18] { + CALL [29] { function: size args: { - LIST [19] { + LIST [30] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } - } - } - result: { - IDENT [32] { - name: @ac:0:0 - } - } + IDENT [31] { + name: @index0 + } + } + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } @@ -1277,37 +1283,37 @@ CALL [1] { } } } - CALL [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index2 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1320,158 +1326,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1539,63 +1551,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1604,37 +1599,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1643,12 +1652,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -1681,87 +1704,87 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - LIST [11] { - elements: { - COMPREHENSION [12] { - iter_var: @it:1:0 - iter_range: { - IDENT [13] { - name: @index0 - } + COMPREHENSION [11] { + iter_var: @it:1:0 + iter_range: { + IDENT [12] { + name: @index0 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { - elements: { - } + } + } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @ac:1:0 } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { - elements: { - CALL [19] { - function: _+_ - args: { - IDENT [20] { - name: @it:1:0 - } - CONSTANT [21] { value: 1 } - } + LIST [17] { + elements: { + CALL [18] { + function: _+_ + args: { + IDENT [19] { + name: @it:1:0 } + CONSTANT [20] { value: 1 } } } } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } + } + } + result: { + IDENT [21] { + name: @ac:1:0 } } } } } - CALL [23] { + CALL [22] { function: _==_ args: { - COMPREHENSION [24] { + COMPREHENSION [23] { iter_var: @it:0:0 iter_range: { - IDENT [25] { + IDENT [24] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [26] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [26] { value: true } } loop_step: { - CALL [28] { + CALL [27] { function: _+_ args: { - IDENT [29] { + IDENT [28] { name: @ac:0:0 } - IDENT [30] { - name: @index2 + LIST [29] { + elements: { + IDENT [30] { + name: @index2 + } + } } } } @@ -1797,107 +1820,107 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:1:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - CONSTANT [7] { value: 2 } - CONSTANT [8] { value: 3 } - } - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [9] { - elements: { - } - } + COMPREHENSION [3] { + iter_var: @it:1:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } - loop_condition: { - CONSTANT [10] { value: true } + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [8] { + elements: { } - loop_step: { + } + } + loop_condition: { + CONSTANT [9] { value: true } + } + loop_step: { + CALL [10] { + function: _?_:_ + args: { CALL [11] { - function: _?_:_ + function: _==_ + args: { + IDENT [12] { + name: @it:1:0 + } + IDENT [13] { + name: @it:0:0 + } + } + } + CALL [14] { + function: _+_ args: { - CALL [12] { - function: _==_ - args: { - IDENT [13] { - name: @it:1:0 - } - IDENT [14] { - name: @it:0:0 - } - } + IDENT [15] { + name: @ac:1:0 } - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @ac:1:0 - } - LIST [17] { - elements: { - IDENT [18] { - name: @it:1:0 - } - } + LIST [16] { + elements: { + IDENT [17] { + name: @it:1:0 } } } - IDENT [19] { - name: @ac:1:0 - } } } - } - result: { - IDENT [20] { + IDENT [18] { name: @ac:1:0 } } } } + result: { + IDENT [19] { + name: @ac:1:0 + } + } } } } - CALL [21] { + CALL [20] { function: _==_ args: { - COMPREHENSION [22] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [23] { + LIST [22] { elements: { - CONSTANT [24] { value: 1 } - CONSTANT [25] { value: 2 } + CONSTANT [23] { value: 1 } + CONSTANT [24] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - LIST [26] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [27] { value: true } + CONSTANT [26] { value: true } } loop_step: { - CALL [28] { + CALL [27] { function: _+_ args: { - IDENT [29] { + IDENT [28] { name: @ac:0:0 } - IDENT [30] { - name: @index0 + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } } } } @@ -1934,90 +1957,90 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:1:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - CONSTANT [7] { value: 2 } - CONSTANT [8] { value: 3 } - } - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [9] { - elements: { - } - } + COMPREHENSION [3] { + iter_var: @it:1:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } } - loop_condition: { - CONSTANT [10] { value: true } + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [8] { + elements: { } - loop_step: { - CALL [11] { - function: _+_ - args: { - IDENT [12] { - name: @ac:1:0 - } - LIST [13] { - elements: { - CALL [14] { - function: _+_ - args: { - IDENT [15] { - name: @it:1:0 - } - CONSTANT [16] { value: 1 } - } + } + } + loop_condition: { + CONSTANT [9] { value: true } + } + loop_step: { + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @ac:1:0 + } + LIST [12] { + elements: { + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @it:1:0 } + CONSTANT [15] { value: 1 } } } } } } - result: { - IDENT [17] { - name: @ac:1:0 - } - } + } + } + result: { + IDENT [16] { + name: @ac:1:0 } } } - COMPREHENSION [18] { + COMPREHENSION [17] { iter_var: @it:0:0 iter_range: { - LIST [19] { + LIST [18] { elements: { - CONSTANT [20] { value: 1 } - CONSTANT [21] { value: 2 } - CONSTANT [22] { value: 3 } + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } } } } accu_var: @ac:0:0 accu_init: { - LIST [23] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [24] { value: true } + CONSTANT [23] { value: true } } loop_step: { - CALL [25] { + CALL [24] { function: _+_ args: { - IDENT [26] { + IDENT [25] { name: @ac:0:0 } - IDENT [27] { - name: @index0 + LIST [26] { + elements: { + IDENT [27] { + name: @index0 + } + } } } } @@ -2207,84 +2230,84 @@ CALL [1] { CONSTANT [12] { value: 2 } } } - LIST [13] { - elements: { - COMPREHENSION [14] { - iter_var: @it:1:0 - iter_range: { - IDENT [15] { - name: @index1 - } + COMPREHENSION [13] { + iter_var: @it:1:0 + iter_range: { + IDENT [14] { + name: @index1 + } + } + accu_var: @ac:1:0 + accu_init: { + LIST [15] { + elements: { } - accu_var: @ac:1:0 - accu_init: { - LIST [16] { - elements: { - } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @ac:1:0 } - } - loop_condition: { - CONSTANT [17] { value: true } - } - loop_step: { - CALL [18] { - function: _+_ - args: { - IDENT [19] { - name: @ac:1:0 - } + LIST [19] { + elements: { LIST [20] { elements: { - LIST [21] { - elements: { - CONSTANT [22] { value: 3 } - CONSTANT [23] { value: 4 } - } - } + CONSTANT [21] { value: 3 } + CONSTANT [22] { value: 4 } } } } } } - result: { - IDENT [24] { - name: @ac:1:0 - } - } + } + } + result: { + IDENT [23] { + name: @ac:1:0 } } } } } - CALL [25] { + CALL [24] { function: _==_ args: { - COMPREHENSION [26] { + COMPREHENSION [25] { iter_var: @it:0:0 iter_range: { - IDENT [27] { + IDENT [26] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [28] { + LIST [27] { elements: { } } } loop_condition: { - CONSTANT [29] { value: true } + CONSTANT [28] { value: true } } loop_step: { - CALL [30] { + CALL [29] { function: _+_ args: { - IDENT [31] { + IDENT [30] { name: @ac:0:0 } - IDENT [32] { - name: @index2 + LIST [31] { + elements: { + IDENT [32] { + name: @index2 + } + } } } } @@ -2428,69 +2451,58 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } - } - } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } - } - } - } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { + COMPREHENSION [3] { iter_var: @it:1:0 iter_range: { - LIST [11] { + LIST [4] { elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } + CONSTANT [5] { value: "foo" } + CONSTANT [6] { value: "bar" } } } } accu_var: @ac:1:0 accu_init: { - LIST [14] { + LIST [7] { elements: { } } } loop_condition: { - CONSTANT [15] { value: true } + CONSTANT [8] { value: true } } loop_step: { - CALL [16] { + CALL [9] { function: _+_ args: { - IDENT [17] { + IDENT [10] { name: @ac:1:0 } - LIST [18] { + LIST [11] { elements: { - LIST [19] { + LIST [12] { elements: { - IDENT [20] { - name: @index0 + CALL [13] { + function: _+_ + args: { + IDENT [14] { + name: @it:1:0 + } + IDENT [15] { + name: @it:1:0 + } + } } - IDENT [21] { - name: @index0 + CALL [16] { + function: _+_ + args: { + IDENT [17] { + name: @it:1:0 + } + IDENT [18] { + name: @it:1:0 + } + } } } } @@ -2500,38 +2512,62 @@ CALL [1] { } } result: { - IDENT [22] { + IDENT [19] { name: @ac:1:0 } } } } + } + COMPREHENSION [20] { + iter_var: @it:0:0 + iter_range: { + IDENT [21] { + name: @index0 + } + } accu_var: @ac:0:0 accu_init: { - LIST [23] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [24] { value: true } + CONSTANT [23] { value: true } } loop_step: { - CALL [25] { + CALL [24] { function: _+_ args: { - IDENT [26] { + IDENT [25] { name: @ac:0:0 } - LIST [27] { + LIST [26] { elements: { - LIST [28] { + LIST [27] { elements: { - IDENT [29] { - name: @index1 + CALL [28] { + function: _+_ + args: { + IDENT [29] { + name: @it:0:0 + } + IDENT [30] { + name: @it:0:0 + } + } } - IDENT [30] { - name: @index1 + CALL [31] { + function: _+_ + args: { + IDENT [32] { + name: @it:0:0 + } + IDENT [33] { + name: @it:0:0 + } + } } } } @@ -2541,7 +2577,7 @@ CALL [1] { } } result: { - IDENT [31] { + IDENT [34] { 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 89e38dc92..272f0d7da 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,125 +1145,131 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } + 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 } } - 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 [11] { - 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 } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ + args: { + IDENT [22] { + name: @ac:0:0 } } - result: { - IDENT [17] { - name: @ac:0:0 + } + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } } } + result: { + IDENT [28] { + name: @ac:0:0 + } + } } - CALL [18] { + CALL [29] { function: size args: { - LIST [19] { + LIST [30] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } - } - } - result: { - IDENT [32] { - name: @ac:0:0 - } - } + IDENT [31] { + name: @index0 + } + } + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } @@ -1271,37 +1277,37 @@ CALL [1] { } } } - CALL [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index2 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1314,158 +1320,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } - } - loop_step: { + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1533,63 +1545,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1598,37 +1593,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1637,12 +1646,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -1675,89 +1698,89 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - CALL [11] { - function: _+_ - args: { + COMPREHENSION [11] { + iter_var: @it:1:0 + iter_range: { IDENT [12] { - name: @ac:0:0 + name: @index0 } + } + accu_var: @ac:1:0 + accu_init: { 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: { + } + } + } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [15] { + function: _+_ + args: { + IDENT [16] { + name: @ac:1:0 + } + LIST [17] { + elements: { 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 } - } - } - } + name: @it:1:0 } + CONSTANT [20] { value: 1 } } } } - result: { - IDENT [24] { - name: @ac:1:0 - } - } } } } } + result: { + IDENT [21] { + name: @ac:1:0 + } + } } } } - CALL [25] { + CALL [22] { function: _==_ args: { - COMPREHENSION [26] { + COMPREHENSION [23] { iter_var: @it:0:0 iter_range: { - IDENT [27] { + IDENT [24] { name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [28] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [29] { value: true } + CONSTANT [26] { value: true } } loop_step: { - IDENT [30] { - name: @index2 + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @ac:0:0 + } + LIST [29] { + elements: { + IDENT [30] { + name: @index2 + } + } + } + } } } result: { @@ -1791,109 +1814,109 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @ac:0:0 + COMPREHENSION [3] { + iter_var: @it:1:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } + } } - LIST [5] { + } + accu_var: @ac:1:0 + accu_init: { + LIST [8] { elements: { - COMPREHENSION [6] { - iter_var: @it:1:0 - iter_range: { - LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - CONSTANT [10] { value: 3 } - } + } + } + } + loop_condition: { + CONSTANT [9] { value: true } + } + loop_step: { + CALL [10] { + function: _?_:_ + args: { + CALL [11] { + function: _==_ + args: { + IDENT [12] { + name: @it:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [11] { - elements: { - } + IDENT [13] { + name: @it:0:0 } } - loop_condition: { - CONSTANT [12] { value: true } - } - loop_step: { - CALL [13] { - function: _?_:_ - args: { - CALL [14] { - function: _==_ - args: { - IDENT [15] { - name: @it:1:0 - } - IDENT [16] { - name: @it:0:0 - } - } - } - CALL [17] { - function: _+_ - args: { - IDENT [18] { - name: @ac:1:0 - } - LIST [19] { - elements: { - IDENT [20] { - name: @it:1:0 - } - } - } - } - } - IDENT [21] { - name: @ac:1:0 + } + CALL [14] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 + } + LIST [16] { + elements: { + IDENT [17] { + name: @it:1:0 } } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } + } + IDENT [18] { + name: @ac:1:0 } } } } + result: { + IDENT [19] { + name: @ac:1:0 + } + } } } } - CALL [23] { + CALL [20] { function: _==_ args: { - COMPREHENSION [24] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [25] { + LIST [22] { elements: { - CONSTANT [26] { value: 1 } - CONSTANT [27] { value: 2 } + CONSTANT [23] { value: 1 } + CONSTANT [24] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - LIST [28] { + LIST [25] { elements: { } } } loop_condition: { - CONSTANT [29] { value: true } + CONSTANT [26] { value: true } } loop_step: { - IDENT [30] { - name: @index0 + CALL [27] { + function: _+_ + args: { + IDENT [28] { + name: @ac:0:0 + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + } } } result: { @@ -1925,95 +1948,95 @@ Source: [1,2,3].map(i, [1, 2, 3].map(i, i + 1)) == [1,2,3].map(j, [1, 2, 3].map( =====> CALL [1] { function: cel.@block - args: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @ac:0:0 + args: { + LIST [2] { + elements: { + COMPREHENSION [3] { + iter_var: @it:1:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } + CONSTANT [6] { value: 2 } + CONSTANT [7] { value: 3 } + } } - LIST [5] { + } + accu_var: @ac:1:0 + accu_init: { + LIST [8] { elements: { - COMPREHENSION [6] { - iter_var: @it:1:0 - iter_range: { - LIST [7] { - elements: { - CONSTANT [8] { value: 1 } - CONSTANT [9] { value: 2 } - CONSTANT [10] { value: 3 } - } - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [11] { - elements: { - } - } - } - loop_condition: { - CONSTANT [12] { value: true } - } - loop_step: { + } + } + } + loop_condition: { + CONSTANT [9] { value: true } + } + loop_step: { + CALL [10] { + function: _+_ + args: { + IDENT [11] { + name: @ac:1:0 + } + LIST [12] { + elements: { CALL [13] { function: _+_ args: { IDENT [14] { - name: @ac:1:0 - } - LIST [15] { - elements: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @it:1:0 - } - CONSTANT [18] { value: 1 } - } - } - } + name: @it:1:0 } + CONSTANT [15] { value: 1 } } } } - result: { - IDENT [19] { - name: @ac:1:0 - } - } } } } } + result: { + IDENT [16] { + name: @ac:1:0 + } + } } - COMPREHENSION [20] { + COMPREHENSION [17] { iter_var: @it:0:0 iter_range: { - LIST [21] { + LIST [18] { elements: { - CONSTANT [22] { value: 1 } - CONSTANT [23] { value: 2 } - CONSTANT [24] { value: 3 } + CONSTANT [19] { value: 1 } + CONSTANT [20] { value: 2 } + CONSTANT [21] { value: 3 } } } } accu_var: @ac:0:0 accu_init: { - LIST [25] { + LIST [22] { elements: { } } } loop_condition: { - CONSTANT [26] { value: true } + CONSTANT [23] { value: true } } loop_step: { - IDENT [27] { - name: @index0 + CALL [24] { + function: _+_ + args: { + IDENT [25] { + name: @ac:0:0 + } + LIST [26] { + elements: { + IDENT [27] { + name: @index0 + } + } + } + } } } result: { @@ -2201,86 +2224,86 @@ CALL [1] { CONSTANT [12] { value: 2 } } } - CALL [13] { - function: _+_ - args: { + COMPREHENSION [13] { + iter_var: @it:1:0 + iter_range: { IDENT [14] { - name: @ac:0:0 + name: @index1 } + } + accu_var: @ac:1:0 + accu_init: { LIST [15] { elements: { - COMPREHENSION [16] { - iter_var: @it:1:0 - iter_range: { - IDENT [17] { - name: @index1 - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [18] { + } + } + } + loop_condition: { + CONSTANT [16] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [18] { + name: @ac:1:0 + } + LIST [19] { + elements: { + LIST [20] { elements: { + CONSTANT [21] { value: 3 } + CONSTANT [22] { value: 4 } } } } - loop_condition: { - CONSTANT [19] { value: true } - } - loop_step: { - CALL [20] { - function: _+_ - args: { - IDENT [21] { - name: @ac:1:0 - } - LIST [22] { - elements: { - LIST [23] { - elements: { - CONSTANT [24] { value: 3 } - CONSTANT [25] { value: 4 } - } - } - } - } - } - } - } - result: { - IDENT [26] { - name: @ac:1:0 - } - } } } } } + result: { + IDENT [23] { + name: @ac:1:0 + } + } } } } - CALL [27] { + CALL [24] { function: _==_ args: { - COMPREHENSION [28] { + COMPREHENSION [25] { iter_var: @it:0:0 iter_range: { - IDENT [29] { + IDENT [26] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [30] { + LIST [27] { elements: { } } } loop_condition: { - CONSTANT [31] { value: true } + CONSTANT [28] { value: true } } loop_step: { - IDENT [32] { - name: @index2 + CALL [29] { + function: _+_ + args: { + IDENT [30] { + name: @ac:0:0 + } + LIST [31] { + elements: { + IDENT [32] { + name: @index2 + } + } + } + } } } result: { @@ -2417,74 +2440,59 @@ CALL [1] { 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: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } +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" } } } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } } } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } - } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { + LIST [16] { elements: { - } - } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { + LIST [6] { elements: { - LIST [19] { - elements: { - IDENT [20] { - name: @index0 + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 } - IDENT [21] { - name: @index0 + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 } } } @@ -2493,39 +2501,55 @@ CALL [1] { } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } } } - accu_var: @ac:0:0 - accu_init: { - LIST [23] { - elements: { - } + result: { + IDENT [18] { + name: @ac:1:0 } } - loop_condition: { - CONSTANT [24] { value: true } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { } - loop_step: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - LIST [27] { + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { elements: { - LIST [28] { - elements: { - IDENT [29] { - name: @index1 + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 } - IDENT [30] { - name: @index1 + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 } } } @@ -2534,11 +2558,11 @@ CALL [1] { } } } - result: { - IDENT [31] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [34] { + 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 e40934fc9..0ae411c0d 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,125 +1142,131 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } + 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 } } - 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 [11] { - 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 } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ + args: { + IDENT [22] { + name: @ac:0:0 } } - result: { - IDENT [17] { - name: @ac:0:0 + } + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } } } + result: { + IDENT [28] { + name: @ac:0:0 + } + } } - CALL [18] { + CALL [29] { function: size args: { - LIST [19] { + LIST [30] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } - } - } - result: { - IDENT [32] { - name: @ac:0:0 - } - } + IDENT [31] { + name: @index0 + } + } + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } @@ -1268,37 +1274,37 @@ CALL [1] { } } } - CALL [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index2 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1311,158 +1317,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1530,63 +1542,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1595,37 +1590,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1634,12 +1643,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -1672,210 +1695,79 @@ CALL [1] { CONSTANT [10] { value: 4 } } } - COMPREHENSION [11] { - iter_var: @it:0:0 - iter_range: { - IDENT [12] { - name: @index0 - } - } - accu_var: @ac:0:0 - accu_init: { - LIST [13] { - elements: { - } - } - } - loop_condition: { - CONSTANT [14] { value: true } - } - loop_step: { - CALL [15] { - function: _+_ - args: { - IDENT [16] { - name: @ac:0:0 - } - LIST [17] { - elements: { - COMPREHENSION [18] { - iter_var: @it:1:0 - iter_range: { - IDENT [19] { - name: @index0 - } - } - accu_var: @ac:1:0 - accu_init: { - LIST [20] { - elements: { - } - } - } - loop_condition: { - CONSTANT [21] { value: true } - } - loop_step: { - CALL [22] { - function: _+_ - args: { - IDENT [23] { - name: @ac:1:0 - } - LIST [24] { - elements: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @it:1:0 - } - CONSTANT [27] { value: 1 } - } - } - } - } - } - } - } - result: { - IDENT [28] { - name: @ac:1:0 - } - } - } - } - } - } - } - } - result: { - IDENT [29] { - name: @ac:0:0 - } - } - } } } - CALL [30] { + CALL [11] { function: _==_ args: { - IDENT [31] { - name: @index2 - } - LIST [32] { - elements: { - IDENT [33] { - name: @index1 - } - IDENT [34] { - name: @index1 - } - IDENT [35] { - name: @index1 - } - } - } - } - } - } -} -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: { - LIST [2] { - elements: { - COMPREHENSION [3] { + COMPREHENSION [12] { iter_var: @it:0:0 iter_range: { - LIST [4] { - elements: { - CONSTANT [5] { value: 1 } - CONSTANT [6] { value: 2 } - } + IDENT [13] { + name: @index0 } } accu_var: @ac:0:0 accu_init: { - LIST [7] { + LIST [14] { elements: { } } } loop_condition: { - CONSTANT [8] { value: true } + CONSTANT [15] { value: true } } loop_step: { - CALL [9] { + CALL [16] { function: _+_ args: { - IDENT [10] { + IDENT [17] { name: @ac:0:0 } - LIST [11] { + LIST [18] { elements: { - COMPREHENSION [12] { + COMPREHENSION [19] { iter_var: @it:1:0 iter_range: { - LIST [13] { - elements: { - CONSTANT [14] { value: 1 } - CONSTANT [15] { value: 2 } - CONSTANT [16] { value: 3 } - } + IDENT [20] { + name: @index0 } } accu_var: @ac:1:0 accu_init: { - LIST [17] { + LIST [21] { elements: { } } } loop_condition: { - CONSTANT [18] { value: true } + CONSTANT [22] { value: true } } loop_step: { - CALL [19] { - function: _?_:_ + CALL [23] { + function: _+_ args: { - CALL [20] { - function: _==_ - args: { - IDENT [21] { - name: @it:1:0 - } - IDENT [22] { - name: @it:0:0 - } - } + IDENT [24] { + name: @ac:1:0 } - CALL [23] { - function: _+_ - args: { - IDENT [24] { - name: @ac:1:0 - } - LIST [25] { - elements: { - IDENT [26] { + LIST [25] { + elements: { + CALL [26] { + function: _+_ + args: { + IDENT [27] { name: @it:1:0 } + CONSTANT [28] { value: 1 } } } } } - IDENT [27] { - name: @ac:1:0 - } } } } result: { - IDENT [28] { + IDENT [29] { name: @ac:1:0 } } @@ -1886,34 +1778,150 @@ CALL [1] { } } result: { - IDENT [29] { + IDENT [30] { name: @ac:0:0 } } } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 + } + IDENT [33] { + name: @index1 + } + IDENT [34] { + name: @index1 + } + } + } } } - CALL [30] { - function: _==_ - args: { - IDENT [31] { - name: @index0 + } +} +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 } + } } - LIST [32] { + } + accu_var: @ac:0:0 + accu_init: { + LIST [24] { elements: { - LIST [33] { - elements: { - CONSTANT [34] { value: 1 } - } + } + } + } + loop_condition: { + CONSTANT [25] { value: true } + } + loop_step: { + CALL [28] { + function: _+_ + args: { + IDENT [26] { + name: @ac:0:0 } - LIST [35] { + LIST [27] { elements: { - CONSTANT [36] { value: 2 } + 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 } + } + } + } } } } @@ -2195,62 +2203,67 @@ CALL [1] { CONSTANT [12] { value: 2 } } } - COMPREHENSION [13] { + } + } + CALL [13] { + function: _==_ + args: { + COMPREHENSION [14] { iter_var: @it:0:0 iter_range: { - IDENT [14] { + IDENT [15] { name: @index1 } } accu_var: @ac:0:0 accu_init: { - LIST [15] { + LIST [16] { elements: { } } } loop_condition: { - CONSTANT [16] { value: true } + CONSTANT [17] { value: true } } loop_step: { - CALL [17] { + CALL [18] { function: _+_ args: { - IDENT [18] { + IDENT [19] { name: @ac:0:0 } - LIST [19] { + LIST [20] { elements: { - COMPREHENSION [20] { + COMPREHENSION [21] { iter_var: @it:1:0 iter_range: { - IDENT [21] { + IDENT [22] { name: @index1 } } accu_var: @ac:1:0 accu_init: { - LIST [22] { + LIST [23] { elements: { } } } loop_condition: { - CONSTANT [23] { value: true } + CONSTANT [24] { value: true } } loop_step: { - CALL [24] { + CALL [25] { function: _+_ args: { - IDENT [25] { + IDENT [26] { name: @ac:1:0 } - LIST [26] { + LIST [27] { elements: { - LIST [27] { + LIST [28] { elements: { - CONSTANT [28] { value: 3 } - CONSTANT [29] { value: 4 } + CONSTANT [29] { value: 3 } + CONSTANT [30] { value: 4 } } } } @@ -2259,7 +2272,7 @@ CALL [1] { } } result: { - IDENT [30] { + IDENT [31] { name: @ac:1:0 } } @@ -2270,25 +2283,17 @@ CALL [1] { } } result: { - IDENT [31] { + IDENT [32] { name: @ac:0:0 } } } - } - } - CALL [32] { - function: _==_ - args: { - IDENT [33] { - name: @index2 - } - LIST [34] { + LIST [33] { elements: { - IDENT [35] { + IDENT [34] { name: @index0 } - IDENT [36] { + IDENT [35] { name: @index0 } } @@ -2411,74 +2416,59 @@ CALL [1] { 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: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } +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" } } } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } } } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } - } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { + LIST [16] { elements: { - } - } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { + LIST [6] { elements: { - LIST [19] { - elements: { - IDENT [20] { - name: @index0 + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 } - IDENT [21] { - name: @index0 + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 } } } @@ -2487,39 +2477,55 @@ CALL [1] { } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } } } - accu_var: @ac:0:0 - accu_init: { - LIST [23] { - elements: { - } + result: { + IDENT [18] { + name: @ac:1:0 } } - loop_condition: { - CONSTANT [24] { value: true } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { } - loop_step: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - LIST [27] { + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { elements: { - LIST [28] { - elements: { - IDENT [29] { - name: @index1 + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 } - IDENT [30] { - name: @index1 + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 } } } @@ -2528,11 +2534,11 @@ CALL [1] { } } } - result: { - IDENT [31] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [34] { + 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 fd78a51a9..feea58534 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,125 +1142,131 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } + 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 } } - 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 [11] { - 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 } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ + args: { + IDENT [22] { + name: @ac:0:0 } } - result: { - IDENT [17] { - name: @ac:0:0 + } + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } } } + result: { + IDENT [28] { + name: @ac:0:0 + } + } } - CALL [18] { + CALL [29] { function: size args: { - LIST [19] { + LIST [30] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } - } - } - result: { - IDENT [32] { - name: @ac:0:0 - } - } + IDENT [31] { + name: @index0 + } + } + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } @@ -1268,37 +1274,37 @@ CALL [1] { } } } - CALL [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index2 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1311,158 +1317,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1530,63 +1542,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1595,37 +1590,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1634,12 +1643,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -2393,74 +2416,59 @@ CALL [1] { 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: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } +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" } } } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } } } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } - } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { + LIST [16] { elements: { - } - } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { + LIST [6] { elements: { - LIST [19] { - elements: { - IDENT [20] { - name: @index0 + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 } - IDENT [21] { - name: @index0 + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 } } } @@ -2469,39 +2477,55 @@ CALL [1] { } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } } } - accu_var: @ac:0:0 - accu_init: { - LIST [23] { - elements: { - } + result: { + IDENT [18] { + name: @ac:1:0 } } - loop_condition: { - CONSTANT [24] { value: true } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { } - loop_step: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - LIST [27] { + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { elements: { - LIST [28] { - elements: { - IDENT [29] { - name: @index1 + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 } - IDENT [30] { - name: @index1 + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 } } } @@ -2510,11 +2534,11 @@ CALL [1] { } } } - result: { - IDENT [31] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [34] { + 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 b273bd6f2..62f065250 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,125 +1130,131 @@ CALL [1] { args: { LIST [2] { elements: { - CALL [3] { - function: size - args: { + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { LIST [4] { elements: { - COMPREHENSION [5] { - iter_var: @it:0:0 - iter_range: { - LIST [6] { - elements: { - CONSTANT [7] { value: 1 } - } + 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 } } - 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 [11] { - 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 } } - loop_step: { - CALL [12] { - function: _||_ - args: { - IDENT [13] { - name: @ac:0:0 - } - CALL [14] { - function: _>_ - args: { - IDENT [15] { - name: @it:0:0 - } - CONSTANT [16] { value: 0 } - } - } - } + } + } + } + } + result: { + IDENT [15] { + name: @ac:0:0 + } + } + } + COMPREHENSION [16] { + iter_var: @it:0:0 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: 2 } + } + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ + args: { + IDENT [22] { + name: @ac:0:0 } } - result: { - IDENT [17] { - name: @ac:0:0 + } + } + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:0 + } + CALL [25] { + function: _>_ + args: { + IDENT [26] { + name: @it:0:0 } + CONSTANT [27] { value: 1 } } } } } } + result: { + IDENT [28] { + name: @ac:0:0 + } + } } - CALL [18] { + CALL [29] { function: size args: { - LIST [19] { + LIST [30] { elements: { - COMPREHENSION [20] { - iter_var: @it:0:0 - iter_range: { - LIST [21] { - elements: { - CONSTANT [22] { value: 2 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [23] { value: false } - } - loop_condition: { - CALL [24] { - function: @not_strictly_false - args: { - CALL [25] { - function: !_ - args: { - IDENT [26] { - name: @ac:0:0 - } - } - } - } - } - } - loop_step: { - CALL [27] { - function: _||_ - args: { - IDENT [28] { - name: @ac:0:0 - } - CALL [29] { - function: _>_ - args: { - IDENT [30] { - name: @it:0:0 - } - CONSTANT [31] { value: 1 } - } - } - } - } - } - result: { - IDENT [32] { - name: @ac:0:0 - } - } + IDENT [31] { + name: @index0 + } + } + } + } + } + CALL [32] { + function: size + args: { + LIST [33] { + elements: { + IDENT [34] { + name: @index1 } } } @@ -1256,37 +1262,37 @@ CALL [1] { } } } - CALL [33] { + CALL [35] { function: _==_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - CALL [35] { + CALL [37] { function: _+_ args: { - CALL [36] { + CALL [38] { function: _+_ args: { - IDENT [37] { - name: @index0 + IDENT [39] { + name: @index2 } - IDENT [38] { - name: @index0 + IDENT [40] { + name: @index2 } } } - IDENT [39] { - name: @index1 + IDENT [41] { + name: @index3 } } } - IDENT [40] { - name: @index1 + IDENT [42] { + name: @index3 } } } - CONSTANT [41] { value: 4 } + CONSTANT [43] { value: 4 } } } } @@ -1299,158 +1305,164 @@ CALL [1] { args: { LIST [2] { elements: { - LIST [3] { - elements: { - COMPREHENSION [4] { - iter_var: @it:0:0 - iter_range: { - LIST [5] { - elements: { - CONSTANT [6] { value: 1 } - } - } - } - accu_var: @ac:0:0 - accu_init: { - CONSTANT [7] { value: false } + COMPREHENSION [3] { + iter_var: @it:0:0 + iter_range: { + LIST [4] { + elements: { + CONSTANT [5] { value: 1 } } - loop_condition: { + } + } + accu_var: @ac:0:0 + accu_init: { + CONSTANT [6] { value: false } + } + loop_condition: { + CALL [7] { + function: @not_strictly_false + args: { CALL [8] { - function: @not_strictly_false + function: !_ args: { - CALL [9] { - function: !_ - args: { - IDENT [10] { - name: @ac:0:0 - } - } + IDENT [9] { + name: @ac:0:0 } } } } - loop_step: { - CALL [11] { - function: _||_ + } + } + loop_step: { + CALL [10] { + function: _||_ + args: { + IDENT [11] { + name: @ac:0:0 + } + CALL [12] { + function: _>_ args: { - IDENT [12] { - name: @ac:0:0 - } - CALL [13] { - function: _>_ - args: { - IDENT [14] { - name: @it:0:0 - } - CONSTANT [15] { value: 0 } - } + IDENT [13] { + name: @it:0:0 } + CONSTANT [14] { value: 0 } } } } - result: { - IDENT [16] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [15] { + name: @ac:0:0 } } } - LIST [17] { - elements: { - 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 } + COMPREHENSION [16] { + iter_var: @it:0:1 + iter_range: { + LIST [17] { + elements: { + CONSTANT [18] { value: "a" } } - loop_condition: { - CALL [22] { - function: @not_strictly_false + } + } + accu_var: @ac:0:1 + accu_init: { + CONSTANT [19] { value: false } + } + loop_condition: { + CALL [20] { + function: @not_strictly_false + args: { + CALL [21] { + function: !_ args: { - CALL [23] { - function: !_ - args: { - IDENT [24] { - name: @ac:0:1 - } - } + IDENT [22] { + name: @ac:0:1 } } } } - loop_step: { + } + } + loop_step: { + CALL [23] { + function: _||_ + args: { + IDENT [24] { + name: @ac:0:1 + } CALL [25] { - function: _||_ + function: _==_ args: { IDENT [26] { - name: @ac:0:1 - } - CALL [27] { - function: _==_ - args: { - IDENT [28] { - name: @it:0:1 - } - CONSTANT [29] { value: "a" } - } + name: @it:0:1 } + CONSTANT [27] { value: "a" } } } } - result: { - IDENT [30] { - name: @ac:0:1 - } - } + } + } + result: { + IDENT [28] { + name: @ac:0:1 + } + } + } + LIST [29] { + elements: { + IDENT [30] { + name: @index0 + } + } + } + LIST [31] { + elements: { + IDENT [32] { + name: @index1 } } } } } - CALL [31] { + CALL [33] { function: _==_ args: { - CALL [32] { + CALL [34] { function: _+_ args: { - CALL [33] { + CALL [35] { function: _+_ args: { - CALL [34] { + CALL [36] { function: _+_ args: { - IDENT [35] { - name: @index0 + IDENT [37] { + name: @index2 } - IDENT [36] { - name: @index0 + IDENT [38] { + name: @index2 } } } - IDENT [37] { - name: @index1 + IDENT [39] { + name: @index3 } } } - IDENT [38] { - name: @index1 + IDENT [40] { + name: @index3 } } } - LIST [39] { + LIST [41] { elements: { - CONSTANT [40] { value: true } - CONSTANT [41] { value: true } CONSTANT [42] { value: true } CONSTANT [43] { value: true } + CONSTANT [44] { value: true } + CONSTANT [45] { value: true } } } } @@ -1518,63 +1530,46 @@ CALL [1] { } } } - 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 [21] { + CALL [16] { function: _&&_ args: { - CALL [22] { + CALL [17] { function: _&&_ args: { - IDENT [23] { + IDENT [18] { name: @index0 } - IDENT [24] { + IDENT [19] { name: @index0 } } } - CALL [25] { + CALL [20] { function: _&&_ args: { - COMPREHENSION [26] { + COMPREHENSION [21] { iter_var: @it:0:0 iter_range: { - LIST [27] { + LIST [22] { elements: { - CONSTANT [28] { value: 1 } + CONSTANT [23] { value: 1 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [29] { value: false } + CONSTANT [24] { value: false } } loop_condition: { - CALL [30] { + CALL [25] { function: @not_strictly_false args: { - CALL [31] { + CALL [26] { function: !_ args: { - IDENT [32] { + IDENT [27] { name: @ac:0:0 } } @@ -1583,37 +1578,51 @@ CALL [1] { } } loop_step: { - IDENT [33] { - name: @index1 + 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 [34] { + IDENT [33] { name: @ac:0:0 } } } - COMPREHENSION [35] { + COMPREHENSION [34] { iter_var: @it:0:0 iter_range: { - LIST [36] { + LIST [35] { elements: { - CONSTANT [37] { value: 2 } + CONSTANT [36] { value: 2 } } } } accu_var: @ac:0:0 accu_init: { - CONSTANT [38] { value: false } + CONSTANT [37] { value: false } } loop_condition: { - CALL [39] { + CALL [38] { function: @not_strictly_false args: { - CALL [40] { + CALL [39] { function: !_ args: { - IDENT [41] { + IDENT [40] { name: @ac:0:0 } } @@ -1622,12 +1631,26 @@ CALL [1] { } } loop_step: { - IDENT [42] { - name: @index1 + 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 [43] { + IDENT [46] { name: @ac:0:0 } } @@ -2381,74 +2404,59 @@ CALL [1] { 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: { - LIST [2] { - elements: { - CALL [3] { - function: _+_ - args: { - IDENT [4] { - name: @it:1:0 - } - IDENT [5] { - name: @it:1:0 - } +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" } } } - CALL [6] { - function: _+_ - args: { - IDENT [7] { - name: @it:0:0 - } - IDENT [8] { - name: @it:0:0 - } + } + accu_var: @ac:1:0 + accu_init: { + LIST [13] { + elements: { } } } - } - COMPREHENSION [9] { - iter_var: @it:0:0 - iter_range: { - COMPREHENSION [10] { - iter_var: @it:1:0 - iter_range: { - LIST [11] { - elements: { - CONSTANT [12] { value: "foo" } - CONSTANT [13] { value: "bar" } - } + loop_condition: { + CONSTANT [14] { value: true } + } + loop_step: { + CALL [17] { + function: _+_ + args: { + IDENT [15] { + name: @ac:1:0 } - } - accu_var: @ac:1:0 - accu_init: { - LIST [14] { + LIST [16] { elements: { - } - } - } - loop_condition: { - CONSTANT [15] { value: true } - } - loop_step: { - CALL [16] { - function: _+_ - args: { - IDENT [17] { - name: @ac:1:0 - } - LIST [18] { + LIST [6] { elements: { - LIST [19] { - elements: { - IDENT [20] { - name: @index0 + CALL [8] { + function: _+_ + args: { + IDENT [7] { + name: @it:1:0 } - IDENT [21] { - name: @index0 + IDENT [9] { + name: @it:1:0 + } + } + } + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:1:0 + } + IDENT [12] { + name: @it:1:0 } } } @@ -2457,39 +2465,55 @@ CALL [1] { } } } - result: { - IDENT [22] { - name: @ac:1:0 - } - } } } - accu_var: @ac:0:0 - accu_init: { - LIST [23] { - elements: { - } + result: { + IDENT [18] { + name: @ac:1:0 } } - loop_condition: { - CONSTANT [24] { value: true } + } + } + accu_var: @ac:0:0 + accu_init: { + LIST [29] { + elements: { } - loop_step: { - CALL [25] { - function: _+_ - args: { - IDENT [26] { - name: @ac:0:0 - } - LIST [27] { + } + } + loop_condition: { + CONSTANT [30] { value: true } + } + loop_step: { + CALL [33] { + function: _+_ + args: { + IDENT [31] { + name: @ac:0:0 + } + LIST [32] { + elements: { + LIST [22] { elements: { - LIST [28] { - elements: { - IDENT [29] { - name: @index1 + CALL [24] { + function: _+_ + args: { + IDENT [23] { + name: @it:0:0 } - IDENT [30] { - name: @index1 + IDENT [25] { + name: @it:0:0 + } + } + } + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:0:0 + } + IDENT [28] { + name: @it:0:0 } } } @@ -2498,11 +2522,11 @@ CALL [1] { } } } - result: { - IDENT [31] { - name: @ac:0:0 - } - } + } + } + result: { + IDENT [34] { + 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 bb02cd934..79f59cd5d 100644 --- a/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline +++ b/optimizer/src/test/resources/subexpression_ast_cascaded_binds.baseline @@ -3407,76 +3407,59 @@ COMPREHENSION [1] { Test case: MACRO_SHADOWED_VARIABLE_2 Source: ["foo", "bar"].map(x, [x + x, x + x]).map(x, [x + x, x + x]) =====> -COMPREHENSION [1] { +COMPREHENSION [35] { iter_var: @it:1 iter_range: { - COMPREHENSION [2] { + COMPREHENSION [19] { iter_var: @it:0 iter_range: { - LIST [3] { + LIST [1] { elements: { - CONSTANT [4] { value: "foo" } - CONSTANT [5] { value: "bar" } + CONSTANT [2] { value: "foo" } + CONSTANT [3] { value: "bar" } } } } accu_var: @ac:0 accu_init: { - LIST [6] { + LIST [13] { elements: { } } } loop_condition: { - CONSTANT [7] { value: true } + CONSTANT [14] { value: true } } loop_step: { - CALL [8] { + CALL [17] { function: _+_ args: { - IDENT [9] { + IDENT [15] { name: @ac:0 } - LIST [10] { + LIST [16] { elements: { - COMPREHENSION [11] { - iter_var: #unused - iter_range: { - LIST [12] { - elements: { - } - } - } - accu_var: @r0 - accu_init: { - CALL [13] { + LIST [6] { + elements: { + CALL [8] { function: _+_ args: { - IDENT [14] { + IDENT [7] { name: @it:0 } - IDENT [15] { + IDENT [9] { name: @it:0 } } } - } - loop_condition: { - CONSTANT [16] { value: false } - } - loop_step: { - IDENT [17] { - name: @r0 - } - } - result: { - LIST [18] { - elements: { - IDENT [19] { - name: @r0 + CALL [11] { + function: _+_ + args: { + IDENT [10] { + name: @it:0 } - IDENT [20] { - name: @r0 + IDENT [12] { + name: @it:0 } } } @@ -3488,7 +3471,7 @@ COMPREHENSION [1] { } } result: { - IDENT [21] { + IDENT [18] { name: @ac:0 } } @@ -3496,61 +3479,44 @@ COMPREHENSION [1] { } accu_var: @ac:1 accu_init: { - LIST [22] { + LIST [29] { elements: { } } } loop_condition: { - CONSTANT [23] { value: true } + CONSTANT [30] { value: true } } loop_step: { - CALL [24] { + CALL [33] { function: _+_ args: { - IDENT [25] { + IDENT [31] { name: @ac:1 } - LIST [26] { + LIST [32] { elements: { - COMPREHENSION [27] { - iter_var: #unused - iter_range: { - LIST [28] { - elements: { - } - } - } - accu_var: @r1 - accu_init: { - CALL [29] { + LIST [22] { + elements: { + CALL [24] { function: _+_ args: { - IDENT [30] { + IDENT [23] { name: @it:1 } - IDENT [31] { + IDENT [25] { name: @it:1 } } } - } - loop_condition: { - CONSTANT [32] { value: false } - } - loop_step: { - IDENT [33] { - name: @r1 - } - } - result: { - LIST [34] { - elements: { - IDENT [35] { - name: @r1 + CALL [27] { + function: _+_ + args: { + IDENT [26] { + name: @it:1 } - IDENT [36] { - name: @r1 + IDENT [28] { + name: @it:1 } } } @@ -3562,7 +3528,7 @@ COMPREHENSION [1] { } } result: { - IDENT [37] { + IDENT [34] { name: @ac:1 } } diff --git a/optimizer/src/test/resources/subexpression_unparsed.baseline b/optimizer/src/test/resources/subexpression_unparsed.baseline index 6b8606a48..6d3414342 100644 --- a/optimizer/src/test/resources/subexpression_unparsed.baseline +++ b/optimizer/src/test/resources/subexpression_unparsed.baseline @@ -4,7 +4,6 @@ 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) @@ -21,7 +20,6 @@ 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) @@ -38,7 +36,6 @@ 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) @@ -55,7 +52,6 @@ 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) @@ -72,7 +68,6 @@ 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) @@ -89,7 +84,6 @@ 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) @@ -106,7 +100,6 @@ 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}) @@ -123,7 +116,6 @@ 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]) @@ -140,7 +132,6 @@ 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) @@ -157,7 +148,6 @@ 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) @@ -174,7 +164,6 @@ 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) @@ -191,7 +180,6 @@ 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) @@ -208,7 +196,6 @@ 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) @@ -225,7 +212,6 @@ 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) @@ -242,7 +228,6 @@ 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) @@ -259,7 +244,6 @@ 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)) @@ -276,7 +260,6 @@ 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) @@ -292,51 +275,48 @@ 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_COMMON_SUBEXPR_ONLY]: 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], [2]], size([@index0.exists(@it:0:0, @it:0:0 > 0)]) + size([@index0.exists(@it:0:0, @it:0:0 > 0)]) + size([@index1.exists(@it:0:0, @it:0:0 > 1)]) + size([@index1.exists(@it:0:0, @it:0:0 > 1)]) == 4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], [2]], size([@index0.exists(@it:0:0, @it:0:0 > 0)]) + size([@index0.exists(@it:0:0, @it:0:0 > 0)]) + size([@index1.exists(@it:0:0, @it:0:0 > 1)]) + size([@index1.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) +[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([[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_6]: 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_7]: 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_8]: 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_9]: 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) 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(@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_COMMON_SUBEXPR_ONLY]: 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], ["a"], [true, true, true, true]], [@index0.exists(@it:0:0, @it:0:0 > 0)] + [@index0.exists(@it:0:0, @it:0:0 > 0)] + [@index1.exists(@it:0:1, @it:0:1 == "a")] + [@index1.exists(@it:0:1, @it:0:1 == "a")] == @index2) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], ["a"], [true, true, true, true]], [@index0.exists(@it:0:0, @it:0:0 > 0)] + [@index0.exists(@it:0:0, @it:0:0 > 0)] + [@index1.exists(@it:0:1, @it:0:1 == "a")] + [@index1.exists(@it:0:1, @it:0:1 == "a")] == @index2) [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]) +[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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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], [@index1]], @index2 + @index2 + @index3 + @index3 == [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(@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) -[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)) +[BLOCK_COMMON_SUBEXPR_ONLY]: 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], [2]], @index0.exists(@it:0:0, @it:0:0 > 0) && @index0.exists(@it:0:0, @it:0:0 > 0) && @index0.exists(@it:0:0, @it:0:0 > 1) && @index1.exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1], [2]], @index0.exists(@it:0:0, @it:0:0 > 0) && @index0.exists(@it:0:0, @it:0:0 > 0) && @index0.exists(@it:0:0, @it:0:0 > 1) && @index1.exists(@it:0:0, @it:0:0 > 1)) +[BLOCK_RECURSION_DEPTH_3]: 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_4]: 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_5]: 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_6]: 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_7]: 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_8]: 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_9]: 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)) 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]] @@ -344,14 +324,13 @@ 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]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index2) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index2) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3], [2, 3, 4], [@index1, @index1, @index1]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index2) [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_5]: 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_6]: 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_7]: 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_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]) @@ -361,14 +340,13 @@ 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]]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [1, 2, 3], [1], [2], [@index2, @index3]], @index0.map(@it:0:0, @index1.filter(@it:1:0, @it:1:0 == @it:0:0)) == @index4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[1], [2]], [1, 2], [1, 2, 3]], @index1.map(@it:0:0, @index2.filter(@it:1:0, @it:1:0 == @it:0:0)) == @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[1], [2]], [1, 2], [1, 2, 3]], @index1.map(@it:0:0, @index2.filter(@it:1:0, @it:1:0 == @it:0:0)) == @index0) [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_5]: 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_6]: 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_7]: [1, 2].map(@it:0:0, [1, 2, 3].filter(@it:1:0, @it:1:0 == @it:0:0)) == [[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]] @@ -378,13 +356,12 @@ 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) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2, 3]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[1, 2, 3]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[1, 2, 3]], @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1)) == @index0.map(@it:0:0, @index0.map(@it:1:0, @it:1:0 + 1))) [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_5]: 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_6]: 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_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) @@ -395,7 +372,6 @@ 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) @@ -412,7 +388,6 @@ 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}) @@ -429,14 +404,13 @@ 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]) +[BLOCK_RECURSION_DEPTH_1]: cel.@block([[1, 2], [3, 4], [@index1, @index1], [@index1], [@index2, @index2]], @index0.map(@it:0:0, @index0.map(@it:1:0, @index1)) == @index4) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@it:1:0, [3, 4]), [@index3]], @index1.map(@it:0:0, @index3) == [@index0, @index0]) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([[[3, 4], [3, 4]], [1, 2], [[3, 4]], @index1.map(@it:1:0, [3, 4])], @index1.map(@it:0:0, @index3) == [@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_5]: 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_6]: 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_7]: 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_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]) @@ -446,11 +420,10 @@ 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) -[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_1]: cel.@block([x - 1, @index0 > 3, @index1 ? @index0 : 5, [@index2]], @index3.exists(@it:0:0, @it:0:0 - 1 > 3) || @index1) +[BLOCK_RECURSION_DEPTH_2]: cel.@block([x - 1 > 3, @index0 ? (x - 1) : 5, [@index1]], @index2.exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_3]: cel.@block([x - 1 > 3, [@index0 ? (x - 1) : 5]], @index1.exists(@it:0:0, @it:0:0 - 1 > 3) || @index0) +[BLOCK_RECURSION_DEPTH_4]: cel.@block([x - 1 > 3], [@index0 ? (x - 1) : 5].exists(@it:0:0, @it:0:0 - 1 > 3) || @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) @@ -461,18 +434,17 @@ 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(@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])) -[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])) +[CASCADED_BINDS]: ["foo", "bar"].map(@it:0, [@it:0 + @it:0, @it:0 + @it:0]).map(@it:1, [@it:1 + @it:1, @it:1 + @it:1]) +[BLOCK_COMMON_SUBEXPR_ONLY]: ["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([["foo", "bar"]], @index0.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_2]: cel.@block([["foo", "bar"]], @index0.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_3]: cel.@block([["foo", "bar"]], @index0.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_4]: cel.@block([["foo", "bar"]], @index0.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_5]: cel.@block([["foo", "bar"].map(@it:1:0, [@it:1:0 + @it:1:0, @it:1:0 + @it:1:0])], @index0.map(@it:0:0, [@it:0:0 + @it:0:0, @it:0:0 + @it:0:0])) +[BLOCK_RECURSION_DEPTH_6]: ["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_7]: ["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_8]: ["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_9]: ["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]) Test case: PRESENCE_TEST Source: has({'a': true}.a) && {'a':true}['a'] @@ -480,7 +452,6 @@ 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"]) @@ -497,7 +468,6 @@ 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) @@ -514,7 +484,6 @@ 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) @@ -531,7 +500,6 @@ 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) @@ -548,7 +516,6 @@ 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) @@ -565,7 +532,6 @@ 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) @@ -582,7 +548,6 @@ 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]) @@ -599,7 +564,6 @@ 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") @@ -616,7 +580,6 @@ 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") @@ -633,7 +596,6 @@ 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) @@ -650,7 +612,6 @@ 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)) @@ -667,7 +628,6 @@ 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")) @@ -684,7 +644,6 @@ 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")) @@ -701,7 +660,6 @@ 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")) @@ -718,7 +676,6 @@ 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)) @@ -735,7 +692,6 @@ 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/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java index d7c917c29..2363bd51c 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java +++ b/parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java @@ -51,6 +51,9 @@ public final CelExpr reportError(String message) { /** Reports a {@link CelIssue} and returns a sentinel {@link CelExpr} that indicates an error. */ public abstract CelExpr reportError(CelIssue error); + /** Returns the default accumulator variable name used by macros implementing comprehensions. */ + public abstract String getAccumulatorVarName(); + /** Retrieves the source location for the given {@link CelExpr} ID. */ public final CelSourceLocation getSourceLocation(CelExpr expr) { return getSourceLocation(expr.id()); diff --git a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java index 3ea54f9e4..0dce8b295 100644 --- a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java @@ -78,8 +78,6 @@ public enum CelStandardMacro { 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) { @@ -123,14 +121,23 @@ private static Optional expandAllMacro( CelExpr accuInit = exprFactory.newBoolLiteral(true); CelExpr condition = exprFactory.newGlobalCall( - Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)); + Operator.NOT_STRICTLY_FALSE.getFunction(), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())); CelExpr step = exprFactory.newGlobalCall( - Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + Operator.LOGICAL_AND.getFunction(), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), + arg1); + CelExpr result = exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()); return Optional.of( exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + arg0.ident().name(), + target, + exprFactory.getAccumulatorVarName(), + accuInit, + condition, + step, + result)); } // CelMacroExpander implementation for CEL's exists() macro. @@ -149,14 +156,23 @@ private static Optional expandExistsMacro( exprFactory.newGlobalCall( Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newGlobalCall( - Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR))); + Operator.LOGICAL_NOT.getFunction(), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()))); CelExpr step = exprFactory.newGlobalCall( - Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + Operator.LOGICAL_OR.getFunction(), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), + arg1); + CelExpr result = exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()); return Optional.of( exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + arg0.ident().name(), + target, + exprFactory.getAccumulatorVarName(), + accuInit, + condition, + step, + result)); } // CelMacroExpander implementation for CEL's exists_one() macro. @@ -178,17 +194,23 @@ private static Optional expandExistsOneMacro( arg1, exprFactory.newGlobalCall( Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), exprFactory.newIntLiteral(1)), - exprFactory.newIdentifier(ACCUMULATOR_VAR)); + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())); CelExpr result = exprFactory.newGlobalCall( Operator.EQUALS.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), exprFactory.newIntLiteral(1)); return Optional.of( exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + arg0.ident().name(), + target, + exprFactory.getAccumulatorVarName(), + accuInit, + condition, + step, + result)); } // CelMacroExpander implementation for CEL's map() macro. @@ -218,7 +240,7 @@ private static Optional expandMapMacro( CelExpr step = exprFactory.newGlobalCall( Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), exprFactory.newList(arg1)); if (arg2 != null) { step = @@ -226,17 +248,17 @@ private static Optional expandMapMacro( Operator.CONDITIONAL.getFunction(), arg2, step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())); } return Optional.of( exprFactory.fold( arg0.ident().name(), target, - ACCUMULATOR_VAR, + exprFactory.getAccumulatorVarName(), accuInit, condition, step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()))); } // CelMacroExpander implementation for CEL's filter() macro. @@ -255,23 +277,23 @@ private static Optional expandFilterMacro( CelExpr step = exprFactory.newGlobalCall( Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()), exprFactory.newList(arg0)); step = exprFactory.newGlobalCall( Operator.CONDITIONAL.getFunction(), arg1, step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())); return Optional.of( exprFactory.fold( arg0.ident().name(), target, - ACCUMULATOR_VAR, + exprFactory.getAccumulatorVarName(), accuInit, condition, step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); + exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()))); } private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) { diff --git a/parser/src/main/java/dev/cel/parser/Parser.java b/parser/src/main/java/dev/cel/parser/Parser.java index 3ec9350ed..b49f81453 100644 --- a/parser/src/main/java/dev/cel/parser/Parser.java +++ b/parser/src/main/java/dev/cel/parser/Parser.java @@ -125,6 +125,8 @@ final class Parser extends CELBaseVisitor { "var", "void", "while"); + private static final String ACCUMULATOR_NAME = "__result__"; + private static final String HIDDEN_ACCUMULATOR_NAME = "@result"; static CelValidationResult parse(CelParserImpl parser, CelSource source, CelOptions options) { if (source.getContent().size() > options.maxExpressionCodePointSize()) { @@ -142,7 +144,11 @@ static CelValidationResult parse(CelParserImpl parser, CelSource source, CelOpti CELParser antlrParser = new CELParser(new CommonTokenStream(antlrLexer)); CelSource.Builder sourceInfo = source.toBuilder(); sourceInfo.setDescription(source.getDescription()); - ExprFactory exprFactory = new ExprFactory(antlrParser, sourceInfo); + ExprFactory exprFactory = + new ExprFactory( + antlrParser, + sourceInfo, + options.enableHiddenAccumulatorVar() ? HIDDEN_ACCUMULATOR_NAME : ACCUMULATOR_NAME); Parser parserImpl = new Parser(parser, options, sourceInfo, exprFactory); ErrorListener errorListener = new ErrorListener(exprFactory); antlrLexer.removeErrorListeners(); @@ -613,6 +619,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; @@ -1032,12 +1039,17 @@ private static final class ExprFactory extends CelMacroExprFactory { private final CelSource.Builder sourceInfo; private final ArrayList issues; private final ArrayDeque positions; + private final String accumulatorVarName; - private ExprFactory(org.antlr.v4.runtime.Parser recognizer, CelSource.Builder sourceInfo) { + private ExprFactory( + org.antlr.v4.runtime.Parser recognizer, + CelSource.Builder sourceInfo, + String accumulatorVarName) { this.recognizer = recognizer; this.sourceInfo = sourceInfo; this.issues = new ArrayList<>(); this.positions = new ArrayDeque<>(1); // Currently this usually contains at most 1 position. + this.accumulatorVarName = accumulatorVarName; } // Implementation of CelExprFactory. @@ -1061,6 +1073,11 @@ public CelExpr reportError(CelIssue error) { return ERROR; } + @Override + public String getAccumulatorVarName() { + return accumulatorVarName; + } + // Internal methods used by the parser but not part of the public API. @FormatMethod @CanIgnoreReturnValue diff --git a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java index 4d110b79e..daac056d4 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java @@ -61,6 +61,11 @@ public CelExpr reportError(CelIssue issue) { return CelExpr.newBuilder().setId(nextExprId()).setConstant(Constants.ERROR).build(); } + @Override + public String getAccumulatorVarName() { + return "__result__"; + } + @Override protected CelSourceLocation getSourceLocation(long exprId) { return CelSourceLocation.NONE; diff --git a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java index a091cc60a..22d40117c 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java @@ -69,7 +69,21 @@ public final class CelParserParameterizedTest extends BaselineTestCase { .setId(1) .setConstant(CelConstant.ofValue(10L)) .build()))) - .setOptions(CelOptions.current().populateMacroCalls(true).build()) + .setOptions( + CelOptions.current() + .populateMacroCalls(true) + .enableHiddenAccumulatorVar(true) + .build()) + .build(); + + private static final CelParser PARSER_WITH_OLD_ACCU_VAR = + PARSER + .toParserBuilder() + .setOptions( + CelOptions.current() + .populateMacroCalls(true) + .enableHiddenAccumulatorVar(false) + .build()) .build(); @Test @@ -110,7 +124,7 @@ public void parser() { runTest(PARSER, "a"); runTest(PARSER, "a?b:c"); runTest(PARSER, "a || b"); - runTest(PARSER, "a || b || c || d || e || f "); + runTest(PARSER, "a || b || c || d || e || f"); runTest(PARSER, "a && b"); runTest(PARSER, "a && b && c && d && e && f && g"); runTest(PARSER, "a && b && c && d || e && f && g && h"); @@ -193,6 +207,17 @@ public void parser() { "while"); } + @Test + public void parser_legacyAccuVar() { + runTest(PARSER_WITH_OLD_ACCU_VAR, "x * 2"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "has(m.f)"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "m.exists_one(v, f)"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "m.all(v, f)"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "m.map(v, f)"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "m.map(v, p, f)"); + runTest(PARSER_WITH_OLD_ACCU_VAR, "m.filter(v, p)"); + } + @Test public void parser_errors() { runTest(PARSER, "*@a | b"); diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index be95fcaef..9ef729d94 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -273,4 +273,18 @@ 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\"))"); + } } diff --git a/parser/src/test/resources/parser.baseline b/parser/src/test/resources/parser.baseline index 455cf24dd..435b92a1f 100644 --- a/parser/src/test/resources/parser.baseline +++ b/parser/src/test/resources/parser.baseline @@ -735,7 +735,7 @@ P: __comprehension__( // Target m^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init 0^#5:int64#, // LoopCondition @@ -744,14 +744,14 @@ P: __comprehension__( _?_:_( f^#4:Expr.Ident#, _+_( - __result__^#7:Expr.Ident#, + @result^#7:Expr.Ident#, 1^#8:int64# )^#9:Expr.Call#, - __result__^#10:Expr.Ident# + @result^#10:Expr.Ident# )^#11:Expr.Call#, // Result _==_( - __result__^#12:Expr.Ident#, + @result^#12:Expr.Ident#, 1^#13:int64# )^#14:Expr.Call#)^#15:Expr.Comprehension# L: __comprehension__( @@ -760,7 +760,7 @@ L: __comprehension__( // Target m^#1[1,0]#, // Accumulator - __result__, + @result, // Init 0^#5[1,12]#, // LoopCondition @@ -769,14 +769,14 @@ L: __comprehension__( _?_:_( f^#4[1,16]#, _+_( - __result__^#7[1,12]#, + @result^#7[1,12]#, 1^#8[1,12]# )^#9[1,12]#, - __result__^#10[1,12]# + @result^#10[1,12]# )^#11[1,12]#, // Result _==_( - __result__^#12[1,12]#, + @result^#12[1,12]#, 1^#13[1,12]# )^#14[1,12]#)^#15[1,12]# M: m^#1:Expr.Ident#.exists_one( @@ -792,40 +792,40 @@ P: __comprehension__( // Target m^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#5:Expr.CreateList#, // LoopCondition true^#6:bool#, // LoopStep _+_( - __result__^#7:Expr.Ident#, + @result^#7:Expr.Ident#, [ f^#4:Expr.Ident# ]^#8:Expr.CreateList# )^#9:Expr.Call#, // Result - __result__^#10:Expr.Ident#)^#11:Expr.Comprehension# + @result^#10:Expr.Ident#)^#11:Expr.Comprehension# L: __comprehension__( // Variable v, // Target m^#1[1,0]#, // Accumulator - __result__, + @result, // Init []^#5[1,5]#, // LoopCondition true^#6[1,5]#, // LoopStep _+_( - __result__^#7[1,5]#, + @result^#7[1,5]#, [ f^#4[1,9]# ]^#8[1,5]# )^#9[1,5]#, // Result - __result__^#10[1,5]#)^#11[1,5]# + @result^#10[1,5]#)^#11[1,5]# M: m^#1:Expr.Ident#.map( v^#3:Expr.Ident#, f^#4:Expr.Ident# @@ -839,7 +839,7 @@ P: __comprehension__( // Target m^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#6:Expr.CreateList#, // LoopCondition @@ -848,22 +848,22 @@ P: __comprehension__( _?_:_( p^#4:Expr.Ident#, _+_( - __result__^#8:Expr.Ident#, + @result^#8:Expr.Ident#, [ f^#5:Expr.Ident# ]^#9:Expr.CreateList# )^#10:Expr.Call#, - __result__^#11:Expr.Ident# + @result^#11:Expr.Ident# )^#12:Expr.Call#, // Result - __result__^#13:Expr.Ident#)^#14:Expr.Comprehension# + @result^#13:Expr.Ident#)^#14:Expr.Comprehension# L: __comprehension__( // Variable v, // Target m^#1[1,0]#, // Accumulator - __result__, + @result, // Init []^#6[1,5]#, // LoopCondition @@ -872,15 +872,15 @@ L: __comprehension__( _?_:_( p^#4[1,9]#, _+_( - __result__^#8[1,5]#, + @result^#8[1,5]#, [ f^#5[1,12]# ]^#9[1,5]# )^#10[1,5]#, - __result__^#11[1,5]# + @result^#11[1,5]# )^#12[1,5]#, // Result - __result__^#13[1,5]#)^#14[1,5]# + @result^#13[1,5]#)^#14[1,5]# M: m^#1:Expr.Ident#.map( v^#3:Expr.Ident#, p^#4:Expr.Ident#, @@ -895,7 +895,7 @@ P: __comprehension__( // Target m^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#5:Expr.CreateList#, // LoopCondition @@ -904,22 +904,22 @@ P: __comprehension__( _?_:_( p^#4:Expr.Ident#, _+_( - __result__^#7:Expr.Ident#, + @result^#7:Expr.Ident#, [ v^#3:Expr.Ident# ]^#8:Expr.CreateList# )^#9:Expr.Call#, - __result__^#10:Expr.Ident# + @result^#10:Expr.Ident# )^#11:Expr.Call#, // Result - __result__^#12:Expr.Ident#)^#13:Expr.Comprehension# + @result^#12:Expr.Ident#)^#13:Expr.Comprehension# L: __comprehension__( // Variable v, // Target m^#1[1,0]#, // Accumulator - __result__, + @result, // Init []^#5[1,8]#, // LoopCondition @@ -928,15 +928,15 @@ L: __comprehension__( _?_:_( p^#4[1,12]#, _+_( - __result__^#7[1,8]#, + @result^#7[1,8]#, [ v^#3[1,9]# ]^#8[1,8]# )^#9[1,8]#, - __result__^#10[1,8]# + @result^#10[1,8]# )^#11[1,8]#, // Result - __result__^#12[1,8]#)^#13[1,8]# + @result^#12[1,8]#)^#13[1,8]# M: m^#1:Expr.Ident#.filter( v^#3:Expr.Ident#, p^#4:Expr.Ident# @@ -1205,7 +1205,7 @@ P: __comprehension__( // Target x^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#19:Expr.CreateList#, // LoopCondition @@ -1218,7 +1218,7 @@ P: __comprehension__( // Target y^#4:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#10:Expr.CreateList#, // LoopCondition @@ -1230,32 +1230,32 @@ P: __comprehension__( 0^#9:int64# )^#8:Expr.Call#, _+_( - __result__^#12:Expr.Ident#, + @result^#12:Expr.Ident#, [ z^#6:Expr.Ident# ]^#13:Expr.CreateList# )^#14:Expr.Call#, - __result__^#15:Expr.Ident# + @result^#15:Expr.Ident# )^#16:Expr.Call#, // Result - __result__^#17:Expr.Ident#)^#18:Expr.Comprehension#, + @result^#17:Expr.Ident#)^#18:Expr.Comprehension#, _+_( - __result__^#21:Expr.Ident#, + @result^#21:Expr.Ident#, [ y^#3:Expr.Ident# ]^#22:Expr.CreateList# )^#23:Expr.Call#, - __result__^#24:Expr.Ident# + @result^#24:Expr.Ident# )^#25:Expr.Call#, // Result - __result__^#26:Expr.Ident#)^#27:Expr.Comprehension# + @result^#26:Expr.Ident#)^#27:Expr.Comprehension# L: __comprehension__( // Variable y, // Target x^#1[1,0]#, // Accumulator - __result__, + @result, // Init []^#19[1,8]#, // LoopCondition @@ -1268,7 +1268,7 @@ L: __comprehension__( // Target y^#4[1,12]#, // Accumulator - __result__, + @result, // Init []^#10[1,20]#, // LoopCondition @@ -1280,25 +1280,25 @@ L: __comprehension__( 0^#9[1,28]# )^#8[1,26]#, _+_( - __result__^#12[1,20]#, + @result^#12[1,20]#, [ z^#6[1,21]# ]^#13[1,20]# )^#14[1,20]#, - __result__^#15[1,20]# + @result^#15[1,20]# )^#16[1,20]#, // Result - __result__^#17[1,20]#)^#18[1,20]#, + @result^#17[1,20]#)^#18[1,20]#, _+_( - __result__^#21[1,8]#, + @result^#21[1,8]#, [ y^#3[1,9]# ]^#22[1,8]# )^#23[1,8]#, - __result__^#24[1,8]# + @result^#24[1,8]# )^#25[1,8]#, // Result - __result__^#26[1,8]#)^#27[1,8]# + @result^#26[1,8]#)^#27[1,8]# M: x^#1:Expr.Ident#.filter( y^#3:Expr.Ident#, ^#18:filter# @@ -1319,7 +1319,7 @@ P: __comprehension__( // Target a^#2:Expr.Ident#.b~test-only~^#4:Expr.Select#, // Accumulator - __result__, + @result, // Init []^#8:Expr.CreateList#, // LoopCondition @@ -1328,22 +1328,22 @@ P: __comprehension__( _?_:_( c^#7:Expr.Ident#, _+_( - __result__^#10:Expr.Ident#, + @result^#10:Expr.Ident#, [ c^#6:Expr.Ident# ]^#11:Expr.CreateList# )^#12:Expr.Call#, - __result__^#13:Expr.Ident# + @result^#13:Expr.Ident# )^#14:Expr.Call#, // Result - __result__^#15:Expr.Ident#)^#16:Expr.Comprehension# + @result^#15:Expr.Ident#)^#16:Expr.Comprehension# L: __comprehension__( // Variable c, // Target a^#2[1,4]#.b~test-only~^#4[1,3]#, // Accumulator - __result__, + @result, // Init []^#8[1,15]#, // LoopCondition @@ -1352,15 +1352,15 @@ L: __comprehension__( _?_:_( c^#7[1,19]#, _+_( - __result__^#10[1,15]#, + @result^#10[1,15]#, [ c^#6[1,16]# ]^#11[1,15]# )^#12[1,15]#, - __result__^#13[1,15]# + @result^#13[1,15]# )^#14[1,15]#, // Result - __result__^#15[1,15]#)^#16[1,15]# + @result^#15[1,15]#)^#16[1,15]# M: ^#4:has#.filter( c^#6:Expr.Ident#, c^#7:Expr.Ident# @@ -1377,7 +1377,7 @@ P: __comprehension__( // Target x^#1:Expr.Ident#, // Accumulator - __result__, + @result, // Init []^#35:Expr.CreateList#, // LoopCondition @@ -1391,62 +1391,62 @@ P: __comprehension__( // Target y^#4:Expr.Ident#, // Accumulator - __result__, + @result, // Init false^#11:bool#, // LoopCondition @not_strictly_false( !_( - __result__^#12:Expr.Ident# + @result^#12:Expr.Ident# )^#13:Expr.Call# )^#14:Expr.Call#, // LoopStep _||_( - __result__^#15:Expr.Ident#, + @result^#15:Expr.Ident#, z^#8:Expr.Ident#.a~test-only~^#10:Expr.Select# )^#16:Expr.Call#, // Result - __result__^#17:Expr.Ident#)^#18:Expr.Comprehension#, + @result^#17:Expr.Ident#)^#18:Expr.Comprehension#, __comprehension__( // Variable z, // Target y^#20:Expr.Ident#, // Accumulator - __result__, + @result, // Init false^#27:bool#, // LoopCondition @not_strictly_false( !_( - __result__^#28:Expr.Ident# + @result^#28:Expr.Ident# )^#29:Expr.Call# )^#30:Expr.Call#, // LoopStep _||_( - __result__^#31:Expr.Ident#, + @result^#31:Expr.Ident#, z^#24:Expr.Ident#.b~test-only~^#26:Expr.Select# )^#32:Expr.Call#, // Result - __result__^#33:Expr.Ident#)^#34:Expr.Comprehension# + @result^#33:Expr.Ident#)^#34:Expr.Comprehension# )^#19:Expr.Call#, _+_( - __result__^#37:Expr.Ident#, + @result^#37:Expr.Ident#, [ y^#3:Expr.Ident# ]^#38:Expr.CreateList# )^#39:Expr.Call#, - __result__^#40:Expr.Ident# + @result^#40:Expr.Ident# )^#41:Expr.Call#, // Result - __result__^#42:Expr.Ident#)^#43:Expr.Comprehension# + @result^#42:Expr.Ident#)^#43:Expr.Comprehension# L: __comprehension__( // Variable y, // Target x^#1[1,0]#, // Accumulator - __result__, + @result, // Init []^#35[1,8]#, // LoopCondition @@ -1460,55 +1460,55 @@ L: __comprehension__( // Target y^#4[1,12]#, // Accumulator - __result__, + @result, // Init false^#11[1,20]#, // LoopCondition @not_strictly_false( !_( - __result__^#12[1,20]# + @result^#12[1,20]# )^#13[1,20]# )^#14[1,20]#, // LoopStep _||_( - __result__^#15[1,20]#, + @result^#15[1,20]#, z^#8[1,28]#.a~test-only~^#10[1,27]# )^#16[1,20]#, // Result - __result__^#17[1,20]#)^#18[1,20]#, + @result^#17[1,20]#)^#18[1,20]#, __comprehension__( // Variable z, // Target y^#20[1,37]#, // Accumulator - __result__, + @result, // Init false^#27[1,45]#, // LoopCondition @not_strictly_false( !_( - __result__^#28[1,45]# + @result^#28[1,45]# )^#29[1,45]# )^#30[1,45]#, // LoopStep _||_( - __result__^#31[1,45]#, + @result^#31[1,45]#, z^#24[1,53]#.b~test-only~^#26[1,52]# )^#32[1,45]#, // Result - __result__^#33[1,45]#)^#34[1,45]# + @result^#33[1,45]#)^#34[1,45]# )^#19[1,34]#, _+_( - __result__^#37[1,8]#, + @result^#37[1,8]#, [ y^#3[1,9]# ]^#38[1,8]# )^#39[1,8]#, - __result__^#40[1,8]# + @result^#40[1,8]# )^#41[1,8]#, // Result - __result__^#42[1,8]#)^#43[1,8]# + @result^#42[1,8]#)^#43[1,8]# M: x^#1:Expr.Ident#.filter( y^#3:Expr.Ident#, _&&_( @@ -1622,4 +1622,4 @@ L: [ I: while =====> P: while^#1:Expr.Ident# -L: while^#1[1,0]# +L: while^#1[1,0]# \ No newline at end of file diff --git a/parser/src/test/resources/parser_legacyAccuVar.baseline b/parser/src/test/resources/parser_legacyAccuVar.baseline new file mode 100644 index 000000000..5f9a48b31 --- /dev/null +++ b/parser/src/test/resources/parser_legacyAccuVar.baseline @@ -0,0 +1,280 @@ +I: x * 2 +=====> +P: _*_( + x^#1:Expr.Ident#, + 2^#3:int64# +)^#2:Expr.Call# +L: _*_( + x^#1[1,0]#, + 2^#3[1,4]# +)^#2[1,2]# + +I: has(m.f) +=====> +P: m^#2:Expr.Ident#.f~test-only~^#4:Expr.Select# +L: m^#2[1,4]#.f~test-only~^#4[1,3]# +M: has( + m^#2:Expr.Ident#.f^#3:Expr.Select# +)^#0:Expr.Call# + +I: m.exists_one(v, f) +=====> +P: __comprehension__( + // Variable + v, + // Target + m^#1:Expr.Ident#, + // Accumulator + __result__, + // Init + 0^#5:int64#, + // LoopCondition + true^#6:bool#, + // LoopStep + _?_:_( + f^#4:Expr.Ident#, + _+_( + __result__^#7:Expr.Ident#, + 1^#8:int64# + )^#9:Expr.Call#, + __result__^#10:Expr.Ident# + )^#11:Expr.Call#, + // Result + _==_( + __result__^#12:Expr.Ident#, + 1^#13:int64# + )^#14:Expr.Call#)^#15:Expr.Comprehension# +L: __comprehension__( + // Variable + v, + // Target + m^#1[1,0]#, + // Accumulator + __result__, + // Init + 0^#5[1,12]#, + // LoopCondition + true^#6[1,12]#, + // LoopStep + _?_:_( + f^#4[1,16]#, + _+_( + __result__^#7[1,12]#, + 1^#8[1,12]# + )^#9[1,12]#, + __result__^#10[1,12]# + )^#11[1,12]#, + // Result + _==_( + __result__^#12[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# +)^#0:Expr.Call# + +I: m.all(v, f) +=====> +P: __comprehension__( + // Variable + v, + // Target + m^#1:Expr.Ident#, + // Accumulator + __result__, + // Init + true^#5:bool#, + // LoopCondition + @not_strictly_false( + __result__^#6:Expr.Ident# + )^#7:Expr.Call#, + // LoopStep + _&&_( + __result__^#8:Expr.Ident#, + f^#4:Expr.Ident# + )^#9:Expr.Call#, + // Result + __result__^#10:Expr.Ident#)^#11:Expr.Comprehension# +L: __comprehension__( + // Variable + v, + // Target + m^#1[1,0]#, + // Accumulator + __result__, + // Init + true^#5[1,5]#, + // LoopCondition + @not_strictly_false( + __result__^#6[1,5]# + )^#7[1,5]#, + // LoopStep + _&&_( + __result__^#8[1,5]#, + f^#4[1,9]# + )^#9[1,5]#, + // Result + __result__^#10[1,5]#)^#11[1,5]# +M: m^#1:Expr.Ident#.all( + v^#3:Expr.Ident#, + f^#4:Expr.Ident# +)^#0:Expr.Call# + +I: m.map(v, f) +=====> +P: __comprehension__( + // Variable + v, + // Target + m^#1:Expr.Ident#, + // Accumulator + __result__, + // Init + []^#5:Expr.CreateList#, + // LoopCondition + true^#6:bool#, + // LoopStep + _+_( + __result__^#7:Expr.Ident#, + [ + f^#4:Expr.Ident# + ]^#8:Expr.CreateList# + )^#9:Expr.Call#, + // Result + __result__^#10:Expr.Ident#)^#11:Expr.Comprehension# +L: __comprehension__( + // Variable + v, + // Target + m^#1[1,0]#, + // Accumulator + __result__, + // Init + []^#5[1,5]#, + // LoopCondition + true^#6[1,5]#, + // LoopStep + _+_( + __result__^#7[1,5]#, + [ + f^#4[1,9]# + ]^#8[1,5]# + )^#9[1,5]#, + // Result + __result__^#10[1,5]#)^#11[1,5]# +M: m^#1:Expr.Ident#.map( + v^#3:Expr.Ident#, + f^#4:Expr.Ident# +)^#0:Expr.Call# + +I: m.map(v, p, f) +=====> +P: __comprehension__( + // Variable + v, + // Target + m^#1:Expr.Ident#, + // Accumulator + __result__, + // Init + []^#6:Expr.CreateList#, + // LoopCondition + true^#7:bool#, + // LoopStep + _?_:_( + p^#4:Expr.Ident#, + _+_( + __result__^#8:Expr.Ident#, + [ + f^#5:Expr.Ident# + ]^#9:Expr.CreateList# + )^#10:Expr.Call#, + __result__^#11:Expr.Ident# + )^#12:Expr.Call#, + // Result + __result__^#13:Expr.Ident#)^#14:Expr.Comprehension# +L: __comprehension__( + // Variable + v, + // Target + m^#1[1,0]#, + // Accumulator + __result__, + // Init + []^#6[1,5]#, + // LoopCondition + true^#7[1,5]#, + // LoopStep + _?_:_( + p^#4[1,9]#, + _+_( + __result__^#8[1,5]#, + [ + f^#5[1,12]# + ]^#9[1,5]# + )^#10[1,5]#, + __result__^#11[1,5]# + )^#12[1,5]#, + // Result + __result__^#13[1,5]#)^#14[1,5]# +M: m^#1:Expr.Ident#.map( + v^#3:Expr.Ident#, + p^#4:Expr.Ident#, + f^#5:Expr.Ident# +)^#0:Expr.Call# + +I: m.filter(v, p) +=====> +P: __comprehension__( + // Variable + v, + // Target + m^#1:Expr.Ident#, + // Accumulator + __result__, + // Init + []^#5:Expr.CreateList#, + // LoopCondition + true^#6:bool#, + // LoopStep + _?_:_( + p^#4:Expr.Ident#, + _+_( + __result__^#7:Expr.Ident#, + [ + v^#3:Expr.Ident# + ]^#8:Expr.CreateList# + )^#9:Expr.Call#, + __result__^#10:Expr.Ident# + )^#11:Expr.Call#, + // Result + __result__^#12:Expr.Ident#)^#13:Expr.Comprehension# +L: __comprehension__( + // Variable + v, + // Target + m^#1[1,0]#, + // Accumulator + __result__, + // Init + []^#5[1,8]#, + // LoopCondition + true^#6[1,8]#, + // LoopStep + _?_:_( + p^#4[1,12]#, + _+_( + __result__^#7[1,8]#, + [ + v^#3[1,9]# + ]^#8[1,8]# + )^#9[1,8]#, + __result__^#10[1,8]# + )^#11[1,8]#, + // Result + __result__^#12[1,8]#)^#13[1,8]# +M: m^#1:Expr.Ident#.filter( + v^#3:Expr.Ident#, + p^#4:Expr.Ident# +)^#0:Expr.Call# \ No newline at end of file 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/BUILD.bazel b/policy/src/test/java/dev/cel/policy/BUILD.bazel index 09a1a98c2..a7b0baf9a 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", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/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 9ff04cfe4..4e17b6ae5 100644 --- a/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java +++ b/policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java @@ -19,7 +19,6 @@ 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; @@ -30,6 +29,7 @@ import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparserFactory; @@ -39,6 +39,7 @@ 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.CelLateFunctionBindings; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import java.io.IOException; import java.util.Map; @@ -212,6 +213,43 @@ public void evaluateYamlPolicy_nestedRuleProducesOptionalOutput() throws Excepti assertThat(evalResult).hasValue(Optional.of(true)); } + @Test + public void evaluateYamlPolicy_lateBoundFunction() throws Exception { + String configSource = + "name: late_bound_function_config\n" + + "functions:\n" + + " - name: 'lateBoundFunc'\n" + + " overloads:\n" + + " - id: 'lateBoundFunc_string'\n" + + " args:\n" + + " - type_name: 'string'\n" + + " return:\n" + + " type_name: 'string'\n"; + CelPolicyConfig celPolicyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel cel = celPolicyConfig.extend(newCel(), CelOptions.DEFAULT); + String policySource = + "name: late_bound_function_policy\n" + + "rule:\n" + + " match:\n" + + " - output: |\n" + + " lateBoundFunc('foo')\n"; + CelPolicy policy = POLICY_PARSER.parse(policySource); + CelAbstractSyntaxTree compiledPolicyAst = + CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy); + String exampleValue = "bar"; + CelLateFunctionBindings lateFunctionBindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from( + "lateBoundFunc_string", String.class, arg -> arg + exampleValue)); + + String evalResult = + (String) + cel.createProgram(compiledPolicyAst) + .eval((unused) -> Optional.empty(), lateFunctionBindings); + + assertThat(evalResult).isEqualTo("foo" + exampleValue); + } + private static final class EvaluablePolicyTestData { private final TestYamlPolicy yamlPolicy; private final PolicyTestCase testCase; 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 = diff --git a/policy/src/test/resources/pb/config.yaml b/policy/src/test/resources/pb/config.yaml index dc38a6a23..d13ce2ae1 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: "google.api.expr.test.v1.proto3" +container: "cel.expr.conformance.proto3" extensions: - name: "strings" version: 2 variables: - name: "spec" type: - type_name: "google.api.expr.test.v1.proto3.TestAllTypes" + type_name: "cel.expr.conformance.proto3.TestAllTypes" diff --git a/publish/cel_version.bzl b/publish/cel_version.bzl index b92d340ca..a0ebb4dd7 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.8.0" +CEL_VERSION = "0.9.0" 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/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index e74420b74..93e8fe8e9 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -10,15 +10,17 @@ 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", ] +# keep sorted INTERPRETER_SOURCES = [ "Activation.java", "CallArgumentChecker.java", @@ -37,32 +39,40 @@ INTERPRETER_SOURCES = [ "UnknownTrackingInterpretable.java", ] +java_library( + name = "cel_type_resolver", + srcs = ["CelTypeResolver.java"], + deps = [ + "//common/types", + "//common/types:type_providers", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + ], +) + java_library( name = "base", srcs = BASE_SOURCES, tags = [ ], deps = [ - ":runtime_helper", "//:auto_value", "//common", "//common:error_codes", "//common:options", - "//common:proto_ast", "//common:runtime_exception", "//common/annotations", "//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", + "//runtime:runtime_helper", + "@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//:com_google_protobuf_protobuf_java_util", - "@maven//:com_google_re2j_re2j", "@maven//:org_jspecify_jspecify", ], ) @@ -76,6 +86,7 @@ java_library( exports = [":base"], deps = [ ":base", + ":cel_type_resolver", ":evaluation_listener", ":runtime_helper", ":unknown_attributes", @@ -84,7 +95,6 @@ java_library( "//common:error_codes", "//common:features", "//common:options", - "//common:proto_ast", "//common:runtime_exception", "//common/annotations", "//common/ast", @@ -92,9 +102,9 @@ java_library( "//common/internal:default_message_factory", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", + "//common/types", "//common/types:cel_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", @@ -133,11 +143,15 @@ java_library( RUNTIME_SOURCES = [ "CelEvaluationException.java", "CelFunctionOverload.java", + "CelFunctionResolver.java", + "CelLateFunctionBindings.java", + "CelResolvedOverload.java", "CelRuntime.java", "CelRuntimeBuilder.java", "CelRuntimeFactory.java", "CelRuntimeLegacyImpl.java", "CelRuntimeLibrary.java", + "CelStandardFunctions.java", "CelVariableResolver.java", "HierarchicalVariableResolver.java", "UnknownContext.java", @@ -150,6 +164,7 @@ java_library( ], deps = [ ":evaluation_listener", + ":runtime_helper", ":runtime_type_provider_legacy", ":unknown_attributes", "//:auto_value", @@ -158,6 +173,7 @@ java_library( "//common:options", "//common/annotations", "//common/internal:cel_descriptor_pools", + "//common/internal:comparison_functions", "//common/internal:default_message_factory", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", @@ -169,6 +185,8 @@ 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//:com_google_re2j_re2j", "@maven//:org_jspecify_jspecify", ], ) @@ -195,11 +213,10 @@ java_library( ":unknown_attributes", "//common", "//common:compiler_common", - "//common:proto_ast", + "//common/ast", "//parser", "//parser:operator", "//parser:parser_builder", - "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_guava_guava", ], ) @@ -228,17 +245,13 @@ java_library( "//common/annotations", "//common/internal:cel_descriptor_pools", "//common/internal:dynamic_proto", - "//common/types", - "//common/types:type_providers", "//common/values", "//common/values:cel_value", "//common/values:cel_value_provider", "//common/values:proto_message_value", "//runtime:interpreter", - "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", - "@maven//:org_jspecify_jspecify", ], ) @@ -249,8 +262,8 @@ java_library( ], deps = [ ":base", + ":unknown_attributes", "//common/annotations", - "@cel_spec//proto/cel/expr:expr_java_proto", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:org_jspecify_jspecify", ], diff --git a/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java b/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java index a3bd6e4b7..b3096fc7a 100644 --- a/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java +++ b/runtime/src/main/java/dev/cel/runtime/CallArgumentChecker.java @@ -14,8 +14,6 @@ package dev.cel.runtime; -import dev.cel.expr.ExprValue; -import dev.cel.expr.UnknownSet; import dev.cel.common.annotations.Internal; import java.util.ArrayList; import java.util.Optional; @@ -32,13 +30,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,14 +74,17 @@ void checkArg(DefaultInterpreter.IntermediateResult arg) { // support for ExprValue unknowns. if (InterpreterUtil.isUnknown(arg.value())) { - ExprValue exprValue = (ExprValue) arg.value(); - exprIds.addAll(exprValue.getUnknown().getExprsList()); + CelUnknownSet unknownSet = (CelUnknownSet) arg.value(); + exprIds.addAll(unknownSet.unknownExprIds()); } } private Optional maybeUnknownFromArg(DefaultInterpreter.IntermediateResult arg) { if (arg.value() instanceof CelUnknownSet) { - return Optional.of((CelUnknownSet) arg.value()); + CelUnknownSet celUnknownSet = (CelUnknownSet) arg.value(); + if (!celUnknownSet.attributes().isEmpty()) { + return Optional.of((CelUnknownSet) arg.value()); + } } if (!acceptPartial) { return resolver.maybePartialUnknown(arg.attribute()); @@ -98,8 +99,7 @@ Optional maybeUnknowns() { } if (!exprIds.isEmpty()) { - return Optional.of( - ExprValue.newBuilder().setUnknown(UnknownSet.newBuilder().addAllExprs(exprIds)).build()); + return Optional.of(CelUnknownSet.create(exprIds)); } return Optional.empty(); diff --git a/runtime/src/main/java/dev/cel/runtime/CelAttributeParser.java b/runtime/src/main/java/dev/cel/runtime/CelAttributeParser.java index 4ad4722da..a14d8bfd5 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelAttributeParser.java +++ b/runtime/src/main/java/dev/cel/runtime/CelAttributeParser.java @@ -16,15 +16,15 @@ import static com.google.common.collect.ImmutableList.toImmutableList; -import dev.cel.expr.Constant; -import dev.cel.expr.Expr; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.google.common.primitives.UnsignedLong; import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.CelValidationException; import dev.cel.common.CelValidationResult; +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.ExprKind.Kind; import dev.cel.parser.CelParser; import dev.cel.parser.CelParserFactory; import dev.cel.parser.Operator; @@ -78,19 +78,18 @@ private static String unescape(String s) { return b.toString(); } - private static CelAttribute.Qualifier parseConst(Constant constExpr) { - switch (constExpr.getConstantKindCase()) { - case BOOL_VALUE: - return CelAttribute.Qualifier.ofBool(constExpr.getBoolValue()); + private static CelAttribute.Qualifier parseConst(CelConstant constExpr) { + switch (constExpr.getKind()) { + case BOOLEAN_VALUE: + return CelAttribute.Qualifier.ofBool(constExpr.booleanValue()); case INT64_VALUE: - return CelAttribute.Qualifier.ofInt(constExpr.getInt64Value()); + return CelAttribute.Qualifier.ofInt(constExpr.int64Value()); case UINT64_VALUE: - return CelAttribute.Qualifier.ofUint(UnsignedLong.fromLongBits(constExpr.getUint64Value())); + return CelAttribute.Qualifier.ofUint(constExpr.uint64Value()); case STRING_VALUE: - return CelAttribute.Qualifier.ofString(unescape(constExpr.getStringValue())); + return CelAttribute.Qualifier.ofString(unescape(constExpr.stringValue())); default: - throw new IllegalArgumentException( - "Unsupported const expr kind: " + constExpr.getConstantKindCase()); + throw new IllegalArgumentException("Unsupported const expr kind: " + constExpr.getKind()); } } @@ -111,35 +110,34 @@ public static CelAttributePattern parsePattern(String attribute) { try { CelAbstractSyntaxTree ast = result.getAst(); ArrayDeque qualifiers = new ArrayDeque<>(); - // TODO: Traverse using CelExpr - Expr node = CelProtoAbstractSyntaxTree.fromCelAst(ast).getExpr(); + CelExpr node = ast.getExpr(); while (node != null) { - switch (node.getExprKindCase()) { - case IDENT_EXPR: - qualifiers.addFirst(CelAttribute.Qualifier.ofString(node.getIdentExpr().getName())); + switch (node.getKind()) { + case IDENT: + qualifiers.addFirst(CelAttribute.Qualifier.ofString(node.ident().name())); node = null; break; - case CALL_EXPR: - Expr.Call callExpr = node.getCallExpr(); - if (!callExpr.getFunction().equals(Operator.INDEX.getFunction()) - || callExpr.getArgsCount() != 2 - || !callExpr.getArgs(1).hasConstExpr()) { + case CALL: + CelCall callExpr = node.call(); + if (!callExpr.function().equals(Operator.INDEX.getFunction()) + || callExpr.args().size() != 2 + || !callExpr.args().get(1).getKind().equals(Kind.CONSTANT)) { throw new IllegalArgumentException( String.format( "Unsupported call expr: %s(%s)", - callExpr.getFunction(), + callExpr.function(), Joiner.on(", ") .join( - callExpr.getArgsList().stream() - .map(Expr::getExprKindCase) + callExpr.args().stream() + .map(CelExpr::getKind) .collect(toImmutableList())))); } - qualifiers.addFirst(parseConst(callExpr.getArgs(1).getConstExpr())); - node = callExpr.getArgs(0); + qualifiers.addFirst(parseConst(callExpr.args().get(1).constant())); + node = callExpr.args().get(0); break; - case SELECT_EXPR: - String field = node.getSelectExpr().getField(); - node = node.getSelectExpr().getOperand(); + case SELECT: + String field = node.select().field(); + node = node.select().operand(); if (field.equals("_" + WILDCARD_ESCAPE)) { qualifiers.addFirst(CelAttribute.Qualifier.ofWildCard()); break; @@ -148,7 +146,7 @@ public static CelAttributePattern parsePattern(String attribute) { break; default: throw new IllegalArgumentException( - "Unsupported expr kind in attribute: " + node.getExprKindCase()); + "Unsupported expr kind in attribute: " + node.exprKind()); } } return CelAttributePattern.create(ImmutableList.copyOf(qualifiers)); diff --git a/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java b/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java index 313077ecf..fa961875b 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java +++ b/runtime/src/main/java/dev/cel/runtime/CelEvaluationException.java @@ -24,18 +24,26 @@ public final class CelEvaluationException extends CelException { public CelEvaluationException(String message) { - super(message); + super(formatErrorMessage(message)); } public CelEvaluationException(String message, Throwable cause) { - super(message, cause); + super(formatErrorMessage(message), cause); } - CelEvaluationException(InterpreterException cause) { - super(cause.getMessage(), cause.getCause()); + public CelEvaluationException(String message, Throwable cause, CelErrorCode errorCode) { + super(formatErrorMessage(message), cause, errorCode); + } + + public CelEvaluationException(String message, CelErrorCode errorCode) { + super(formatErrorMessage(message), errorCode); } CelEvaluationException(InterpreterException cause, CelErrorCode errorCode) { super(cause.getMessage(), cause.getCause(), errorCode); } + + private static String formatErrorMessage(String message) { + return String.format("evaluation error: %s", message); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java b/runtime/src/main/java/dev/cel/runtime/CelFunctionOverload.java index 2ea1cb529..f924c7d62 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,10 +19,7 @@ /** 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; +public interface CelFunctionOverload extends FunctionOverload { /** * Helper interface for describing unary functions where the type-parameter is used to improve @@ -30,9 +27,7 @@ public interface CelFunctionOverload { */ @Immutable @FunctionalInterface - interface Unary { - Object apply(T arg) throws CelEvaluationException; - } + interface Unary extends FunctionOverload.Unary {} /** * Helper interface for describing binary functions where the type parameters are used to improve @@ -40,7 +35,5 @@ interface Unary { */ @Immutable @FunctionalInterface - interface Binary { - Object apply(T1 arg1, T2 arg2) throws CelEvaluationException; - } + interface Binary extends FunctionOverload.Binary {} } 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..d769ff238 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelFunctionResolver.java @@ -0,0 +1,24 @@ +// 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 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..24522b114 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,30 @@ 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()); + } + + /** + * Evaluate a compiled program with {@code mapValue} and late-bound functions {@code + * lateBoundFunctionResolver}. + */ + public Object eval(Map mapValue, CelFunctionResolver lateBoundFunctionResolver) + throws CelEvaluationException { + return evalInternal( + Activation.copyOf(mapValue), + lateBoundFunctionResolver, + CelEvaluationListener.noOpListener()); + } + /** * Trace evaluates a compiled program without any variables and invokes the listener as * evaluation progresses through the AST. @@ -99,6 +124,33 @@ 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); + } + + /** + * Trace evaluates a compiled program using a {@code mapValue} as the source of input variables + * and late-bound functions {@code lateBoundFunctionResolver}. The listener is invoked as + * evaluation progresses through the AST. + */ + public Object trace( + Map mapValue, + CelFunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws CelEvaluationException { + return evalInternal(Activation.copyOf(mapValue), lateBoundFunctionResolver, listener); + } + /** * Advance evaluation based on the current unknown context. * @@ -109,23 +161,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 +206,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 +246,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: * *

    *
  • unary member function: _ diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java index 47187e4d3..4ca72b674 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java @@ -153,6 +153,14 @@ public interface CelRuntimeBuilder { @CanIgnoreReturnValue CelRuntimeBuilder setStandardEnvironmentEnabled(boolean value); + /** + * Override the standard functions for the runtime. This can be used to subset the standard + * environment to only expose the desired function overloads to the runtime. {@link + * #setStandardEnvironmentEnabled(boolean)} must be set to false for this to take effect. + */ + @CanIgnoreReturnValue + CelRuntimeBuilder setStandardFunctions(CelStandardFunctions standardFunctions); + /** Adds one or more libraries for runtime. */ @CanIgnoreReturnValue CelRuntimeBuilder addLibraries(CelRuntimeLibrary... libraries); diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index f5f96e5ca..dbfaf98c3 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -43,6 +43,9 @@ import dev.cel.common.types.CelTypes; import dev.cel.common.values.CelValueProvider; import dev.cel.common.values.ProtoMessageValueProvider; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Arithmetic; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Comparison; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Conversions; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -87,7 +90,7 @@ public static CelRuntimeBuilder newBuilder() { public static final class Builder implements CelRuntimeBuilder { private final ImmutableSet.Builder fileTypes; - private final HashMap functionBindings; + private final HashMap customFunctionBindings; private final ImmutableSet.Builder celRuntimeLibraries; @SuppressWarnings("unused") @@ -97,6 +100,7 @@ public static final class Builder implements CelRuntimeBuilder { private Function customTypeFactory; private ExtensionRegistry extensionRegistry; private CelValueProvider celValueProvider; + private CelStandardFunctions overriddenStandardFunctions; @Override public CelRuntimeBuilder setOptions(CelOptions options) { @@ -111,7 +115,7 @@ public CelRuntimeBuilder addFunctionBindings(CelFunctionBinding... bindings) { @Override public CelRuntimeBuilder addFunctionBindings(Iterable bindings) { - bindings.forEach(o -> functionBindings.putIfAbsent(o.getOverloadId(), o)); + bindings.forEach(o -> customFunctionBindings.putIfAbsent(o.getOverloadId(), o)); return this; } @@ -160,6 +164,12 @@ public CelRuntimeBuilder setStandardEnvironmentEnabled(boolean value) { return this; } + @Override + public CelRuntimeBuilder setStandardFunctions(CelStandardFunctions standardFunctions) { + this.overriddenStandardFunctions = standardFunctions; + return this; + } + @Override public CelRuntimeBuilder addLibraries(CelRuntimeLibrary... libraries) { checkNotNull(libraries); @@ -184,7 +194,7 @@ public CelRuntimeBuilder setExtensionRegistry(ExtensionRegistry extensionRegistr // and shouldn't be exposed to the public. @VisibleForTesting Map getFunctionBindings() { - return this.functionBindings; + return this.customFunctionBindings; } @VisibleForTesting @@ -200,6 +210,11 @@ ImmutableSet.Builder getFileTypes() { /** Build a new {@code CelRuntimeLegacyImpl} instance from the builder config. */ @Override public CelRuntimeLegacyImpl build() { + if (standardEnvironmentEnabled && overriddenStandardFunctions != null) { + throw new IllegalArgumentException( + "setStandardEnvironmentEnabled must be set to false to override standard function" + + " bindings."); + } // Add libraries, such as extensions celRuntimeLibraries.build().forEach(celLibrary -> celLibrary.setRuntimeOptions(this)); @@ -227,26 +242,33 @@ public CelRuntimeLegacyImpl build() { DynamicProto dynamicProto = DynamicProto.create(runtimeTypeFactory); - DefaultDispatcher dispatcher = - DefaultDispatcher.create(options, dynamicProto, standardEnvironmentEnabled); - - ImmutableMap functionBindingMap = - ImmutableMap.copyOf(functionBindings); - functionBindingMap.forEach( - (String overloadId, CelFunctionBinding func) -> - dispatcher.add( - overloadId, - func.getArgTypes(), - (args) -> { - try { - return func.getDefinition().apply(args); - } catch (CelEvaluationException e) { - throw new InterpreterException.Builder(e.getMessage()) - .setCause(e) - .setErrorCode(e.getErrorCode()) - .build(); - } - })); + ImmutableMap.Builder functionBindingsBuilder = + ImmutableMap.builder(); + for (CelFunctionBinding standardFunctionBinding : newStandardFunctionBindings(dynamicProto)) { + functionBindingsBuilder.put( + standardFunctionBinding.getOverloadId(), standardFunctionBinding); + } + + functionBindingsBuilder.putAll(customFunctionBindings); + + DefaultDispatcher dispatcher = DefaultDispatcher.create(); + functionBindingsBuilder + .buildOrThrow() + .forEach( + (String overloadId, CelFunctionBinding func) -> + dispatcher.add( + overloadId, + func.getArgTypes(), + (args) -> { + try { + return func.getDefinition().apply(args); + } catch (CelEvaluationException e) { + throw new InterpreterException.Builder(e.getMessage()) + .setCause(e) + .setErrorCode(e.getErrorCode()) + .build(); + } + })); RuntimeTypeProvider runtimeTypeProvider; @@ -266,7 +288,66 @@ public CelRuntimeLegacyImpl build() { } return new CelRuntimeLegacyImpl( - new DefaultInterpreter(runtimeTypeProvider, dispatcher, options), options, this); + new DefaultInterpreter(runtimeTypeProvider, dispatcher.immutableCopy(), options), + options, + this); + } + + private ImmutableSet newStandardFunctionBindings( + DynamicProto dynamicProto) { + CelStandardFunctions celStandardFunctions; + if (standardEnvironmentEnabled) { + celStandardFunctions = + CelStandardFunctions.newBuilder() + .filterFunctions( + (standardFunction, standardOverload) -> { + switch (standardFunction) { + case INT: + if (standardOverload.equals(Conversions.INT64_TO_INT64)) { + // Note that we require UnsignedLong flag here to avoid ambiguous + // overloads against "uint64_to_int64", because they both use the same + // Java Long class. We skip adding this identity function if the flag is + // disabled. + return options.enableUnsignedLongs(); + } + break; + case TIMESTAMP: + // TODO: Remove this flag guard once the feature has been + // auto-enabled. + if (standardOverload.equals(Conversions.INT64_TO_TIMESTAMP)) { + return options.enableTimestampEpoch(); + } + break; + case STRING: + return options.enableStringConversion(); + case ADD: + Arithmetic arithmetic = (Arithmetic) standardOverload; + if (arithmetic.equals(Arithmetic.ADD_STRING)) { + return options.enableStringConcatenation(); + } + if (arithmetic.equals(Arithmetic.ADD_LIST)) { + return options.enableListConcatenation(); + } + break; + default: + if (standardOverload instanceof Comparison + && !options.enableHeterogeneousNumericComparisons()) { + Comparison comparison = (Comparison) standardOverload; + return !comparison.isHeterogeneousComparison(); + } + break; + } + + return true; + }) + .build(); + } else if (overriddenStandardFunctions != null) { + celStandardFunctions = overriddenStandardFunctions; + } else { + return ImmutableSet.of(); + } + + return celStandardFunctions.newFunctionBindings(dynamicProto, options); } private static CelDescriptorPool newDescriptorPool( @@ -292,7 +373,7 @@ private static ProtoMessageFactory maybeCombineMessageFactory( private Builder() { this.options = CelOptions.newBuilder().build(); this.fileTypes = ImmutableSet.builder(); - this.functionBindings = new HashMap<>(); + this.customFunctionBindings = new HashMap<>(); this.celRuntimeLibraries = ImmutableSet.builder(); this.extensionRegistry = ExtensionRegistry.getEmptyRegistry(); this.customTypeFactory = null; @@ -309,7 +390,7 @@ private Builder(Builder builder) { // 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); + this.customFunctionBindings = new HashMap<>(builder.customFunctionBindings); } private static ImmutableSet.Builder deepCopy(ImmutableSet.Builder builderToCopy) { diff --git a/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java b/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java new file mode 100644 index 000000000..bd1fc45f9 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java @@ -0,0 +1,2094 @@ +// 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.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableSet; +import com.google.common.primitives.Ints; +import com.google.common.primitives.UnsignedLong; +import com.google.common.primitives.UnsignedLongs; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import com.google.re2j.PatternSyntaxException; +import dev.cel.common.CelErrorCode; +import dev.cel.common.CelOptions; +import dev.cel.common.internal.ComparisonFunctions; +import dev.cel.common.internal.DynamicProto; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Arithmetic; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.BooleanOperator; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Comparison; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Conversions; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.DateTime; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Index; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.InternalOperator; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Relation; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Size; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.StringMatchers; +import java.math.BigDecimal; +import java.text.ParseException; +import java.time.DateTimeException; +import java.time.DayOfWeek; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** Runtime function bindings for the standard functions in CEL. */ +@Immutable +public final class CelStandardFunctions { + private static final String UTC = "UTC"; + + private final ImmutableSet standardOverloads; + + /** + * Enumeration of Standard Function bindings. + * + *

    Note: The conditional, logical_or, logical_and, not_strictly_false, and type functions are + * currently special-cased, and does not appear in this enum. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public enum StandardFunction { + LOGICAL_NOT(BooleanOperator.LOGICAL_NOT), + IN(InternalOperator.IN_LIST, InternalOperator.IN_MAP), + EQUALS(Relation.EQUALS), + NOT_EQUALS(Relation.NOT_EQUALS), + BOOL(Conversions.BOOL_TO_BOOL, Conversions.STRING_TO_BOOL), + ADD( + Arithmetic.ADD_INT64, + Arithmetic.ADD_UINT64, + Arithmetic.ADD_DOUBLE, + Arithmetic.ADD_STRING, + Arithmetic.ADD_BYTES, + Arithmetic.ADD_LIST, + Arithmetic.ADD_TIMESTAMP_DURATION, + Arithmetic.ADD_DURATION_TIMESTAMP, + Arithmetic.ADD_DURATION_DURATION), + SUBTRACT( + Arithmetic.SUBTRACT_INT64, + Arithmetic.SUBTRACT_TIMESTAMP_TIMESTAMP, + Arithmetic.SUBTRACT_TIMESTAMP_DURATION, + Arithmetic.SUBTRACT_UINT64, + Arithmetic.SUBTRACT_DOUBLE, + Arithmetic.SUBTRACT_DURATION_DURATION), + MULTIPLY(Arithmetic.MULTIPLY_INT64, Arithmetic.MULTIPLY_DOUBLE, Arithmetic.MULTIPLY_UINT64), + DIVIDE(Arithmetic.DIVIDE_DOUBLE, Arithmetic.DIVIDE_INT64, Arithmetic.DIVIDE_UINT64), + MODULO(Arithmetic.MODULO_INT64, Arithmetic.MODULO_UINT64), + NEGATE(Arithmetic.NEGATE_INT64, Arithmetic.NEGATE_DOUBLE), + INDEX(Index.INDEX_LIST, Index.INDEX_MAP), + SIZE( + Size.SIZE_STRING, + Size.SIZE_BYTES, + Size.SIZE_LIST, + Size.SIZE_MAP, + Size.STRING_SIZE, + Size.BYTES_SIZE, + Size.LIST_SIZE, + Size.MAP_SIZE), + INT( + Conversions.INT64_TO_INT64, + Conversions.UINT64_TO_INT64, + Conversions.DOUBLE_TO_INT64, + Conversions.STRING_TO_INT64, + Conversions.TIMESTAMP_TO_INT64), + UINT( + Conversions.UINT64_TO_UINT64, + Conversions.INT64_TO_UINT64, + Conversions.DOUBLE_TO_UINT64, + Conversions.STRING_TO_UINT64), + DOUBLE( + Conversions.DOUBLE_TO_DOUBLE, + Conversions.INT64_TO_DOUBLE, + Conversions.STRING_TO_DOUBLE, + Conversions.UINT64_TO_DOUBLE), + STRING( + Conversions.STRING_TO_STRING, + Conversions.INT64_TO_STRING, + Conversions.DOUBLE_TO_STRING, + Conversions.BYTES_TO_STRING, + Conversions.TIMESTAMP_TO_STRING, + Conversions.DURATION_TO_STRING, + Conversions.UINT64_TO_STRING), + BYTES(Conversions.BYTES_TO_BYTES, Conversions.STRING_TO_BYTES), + DURATION(Conversions.DURATION_TO_DURATION, Conversions.STRING_TO_DURATION), + TIMESTAMP( + Conversions.STRING_TO_TIMESTAMP, + Conversions.TIMESTAMP_TO_TIMESTAMP, + Conversions.INT64_TO_TIMESTAMP), + DYN(Conversions.TO_DYN), + MATCHES(StringMatchers.MATCHES, StringMatchers.MATCHES_STRING), + CONTAINS(StringMatchers.CONTAINS_STRING), + ENDS_WITH(StringMatchers.ENDS_WITH_STRING), + STARTS_WITH(StringMatchers.STARTS_WITH_STRING), + // Date/time Functions + GET_FULL_YEAR(DateTime.TIMESTAMP_TO_YEAR, DateTime.TIMESTAMP_TO_YEAR_WITH_TZ), + GET_MONTH(DateTime.TIMESTAMP_TO_MONTH, DateTime.TIMESTAMP_TO_MONTH_WITH_TZ), + GET_DAY_OF_YEAR(DateTime.TIMESTAMP_TO_DAY_OF_YEAR, DateTime.TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ), + GET_DAY_OF_MONTH( + DateTime.TIMESTAMP_TO_DAY_OF_MONTH, DateTime.TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ), + GET_DATE( + DateTime.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED, + DateTime.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ), + GET_DAY_OF_WEEK(DateTime.TIMESTAMP_TO_DAY_OF_WEEK, DateTime.TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ), + + GET_HOURS( + DateTime.TIMESTAMP_TO_HOURS, + DateTime.TIMESTAMP_TO_HOURS_WITH_TZ, + DateTime.DURATION_TO_HOURS), + GET_MINUTES( + DateTime.TIMESTAMP_TO_MINUTES, + DateTime.TIMESTAMP_TO_MINUTES_WITH_TZ, + DateTime.DURATION_TO_MINUTES), + GET_SECONDS( + DateTime.TIMESTAMP_TO_SECONDS, + DateTime.TIMESTAMP_TO_SECONDS_WITH_TZ, + DateTime.DURATION_TO_SECONDS), + GET_MILLISECONDS( + DateTime.TIMESTAMP_TO_MILLISECONDS, + DateTime.TIMESTAMP_TO_MILLISECONDS_WITH_TZ, + DateTime.DURATION_TO_MILLISECONDS), + LESS( + Comparison.LESS_BOOL, + Comparison.LESS_INT64, + Comparison.LESS_UINT64, + Comparison.LESS_DOUBLE, + Comparison.LESS_STRING, + Comparison.LESS_BYTES, + Comparison.LESS_TIMESTAMP, + Comparison.LESS_DURATION, + Comparison.LESS_INT64_UINT64, + Comparison.LESS_UINT64_INT64, + Comparison.LESS_INT64_DOUBLE, + Comparison.LESS_DOUBLE_INT64, + Comparison.LESS_UINT64_DOUBLE, + Comparison.LESS_DOUBLE_UINT64), + LESS_EQUALS( + Comparison.LESS_EQUALS_BOOL, + Comparison.LESS_EQUALS_INT64, + Comparison.LESS_EQUALS_UINT64, + Comparison.LESS_EQUALS_DOUBLE, + Comparison.LESS_EQUALS_STRING, + Comparison.LESS_EQUALS_BYTES, + Comparison.LESS_EQUALS_TIMESTAMP, + Comparison.LESS_EQUALS_DURATION, + Comparison.LESS_EQUALS_INT64_UINT64, + Comparison.LESS_EQUALS_UINT64_INT64, + Comparison.LESS_EQUALS_INT64_DOUBLE, + Comparison.LESS_EQUALS_DOUBLE_INT64, + Comparison.LESS_EQUALS_UINT64_DOUBLE, + Comparison.LESS_EQUALS_DOUBLE_UINT64), + GREATER( + Comparison.GREATER_BOOL, + Comparison.GREATER_INT64, + Comparison.GREATER_UINT64, + Comparison.GREATER_DOUBLE, + Comparison.GREATER_STRING, + Comparison.GREATER_BYTES, + Comparison.GREATER_TIMESTAMP, + Comparison.GREATER_DURATION, + Comparison.GREATER_INT64_UINT64, + Comparison.GREATER_UINT64_INT64, + Comparison.GREATER_INT64_DOUBLE, + Comparison.GREATER_DOUBLE_INT64, + Comparison.GREATER_UINT64_DOUBLE, + Comparison.GREATER_DOUBLE_UINT64), + GREATER_EQUALS( + Comparison.GREATER_EQUALS_BOOL, + Comparison.GREATER_EQUALS_BYTES, + Comparison.GREATER_EQUALS_DOUBLE, + Comparison.GREATER_EQUALS_DURATION, + Comparison.GREATER_EQUALS_INT64, + Comparison.GREATER_EQUALS_STRING, + Comparison.GREATER_EQUALS_TIMESTAMP, + Comparison.GREATER_EQUALS_UINT64, + Comparison.GREATER_EQUALS_INT64_UINT64, + Comparison.GREATER_EQUALS_UINT64_INT64, + Comparison.GREATER_EQUALS_INT64_DOUBLE, + Comparison.GREATER_EQUALS_DOUBLE_INT64, + Comparison.GREATER_EQUALS_UINT64_DOUBLE, + Comparison.GREATER_EQUALS_DOUBLE_UINT64), + OPTIONAL( + Overload.OptionalValue.SELECT_OPTIONAL_FIELD, + Overload.OptionalValue.MAP_OPTINDEX_OPTIONAL_VALUE, + Overload.OptionalValue.OPTIONAL_MAP_OPTINDEX_OPTIONAL_VALUE, + Overload.OptionalValue.OPTIONAL_MAP_INDEX_VALUE, + Overload.OptionalValue.OPTIONAL_LIST_INDEX_INT, + Overload.OptionalValue.LIST_OPTINDEX_OPTIONAL_INT, + Overload.OptionalValue.OPTIONAL_LIST_OPTINDEX_OPTIONAL_INT); + + /** Container class for CEL standard function overloads. */ + public static final class Overload { + + /** Overloads for internal functions that may have been rewritten by macros (ex: @in) */ + public enum InternalOperator implements StandardOverload { + IN_LIST( + (bindingHelper) -> + CelFunctionBinding.from( + "in_list", + Object.class, + List.class, + (Object value, List list) -> + bindingHelper.runtimeEquality.inList( + list, value, bindingHelper.celOptions))), + IN_MAP( + (bindingHelper) -> + CelFunctionBinding.from( + "in_map", + Object.class, + Map.class, + (Object key, Map map) -> + bindingHelper.runtimeEquality.inMap(map, key, bindingHelper.celOptions))); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + InternalOperator(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for functions that test relations. */ + public enum Relation implements StandardOverload { + EQUALS( + (bindingHelper) -> + CelFunctionBinding.from( + "equals", + Object.class, + Object.class, + (Object x, Object y) -> + bindingHelper.runtimeEquality.objectEquals( + x, y, bindingHelper.celOptions))), + NOT_EQUALS( + (bindingHelper) -> + CelFunctionBinding.from( + "not_equals", + Object.class, + Object.class, + (Object x, Object y) -> + !bindingHelper.runtimeEquality.objectEquals( + x, y, bindingHelper.celOptions))); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Relation(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for performing arithmetic operations. */ + public enum Arithmetic implements StandardOverload { + ADD_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "add_int64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.int64Add(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + ADD_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "add_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> { + try { + return RuntimeHelpers.uint64Add(x, y); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } else { + return CelFunctionBinding.from( + "add_uint64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.uint64Add(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } + }), + ADD_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "add_bytes", ByteString.class, ByteString.class, ByteString::concat)), + ADD_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from("add_double", Double.class, Double.class, Double::sum)), + ADD_DURATION_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "add_duration_duration", Duration.class, Duration.class, Durations::add)), + ADD_TIMESTAMP_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "add_timestamp_duration", Timestamp.class, Duration.class, Timestamps::add)), + ADD_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "add_string", String.class, String.class, (String x, String y) -> x + y)), + ADD_DURATION_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "add_duration_timestamp", + Duration.class, + Timestamp.class, + (Duration x, Timestamp y) -> Timestamps.add(y, x))), + ADD_LIST( + (bindingHelper) -> + CelFunctionBinding.from( + "add_list", List.class, List.class, RuntimeHelpers::concat)), + SUBTRACT_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "subtract_int64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.int64Subtract(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + SUBTRACT_TIMESTAMP_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "subtract_timestamp_timestamp", + Timestamp.class, + Timestamp.class, + (Timestamp x, Timestamp y) -> Timestamps.between(y, x))), + SUBTRACT_TIMESTAMP_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "subtract_timestamp_duration", + Timestamp.class, + Duration.class, + Timestamps::subtract)), + SUBTRACT_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "subtract_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> { + try { + return RuntimeHelpers.uint64Subtract(x, y); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } else { + return CelFunctionBinding.from( + "subtract_uint64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.uint64Subtract(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } + }), + SUBTRACT_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "subtract_double", Double.class, Double.class, (Double x, Double y) -> x - y)), + SUBTRACT_DURATION_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "subtract_duration_duration", + Duration.class, + Duration.class, + Durations::subtract)), + MULTIPLY_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "multiply_int64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.int64Multiply(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + MULTIPLY_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "multiply_double", Double.class, Double.class, (Double x, Double y) -> x * y)), + MULTIPLY_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "multiply_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> { + try { + return RuntimeHelpers.uint64Multiply(x, y); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } else { + return CelFunctionBinding.from( + "multiply_uint64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.uint64Multiply(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + }); + } + }), + DIVIDE_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "divide_double", Double.class, Double.class, (Double x, Double y) -> x / y)), + DIVIDE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "divide_int64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return RuntimeHelpers.int64Divide(x, y, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + DIVIDE_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "divide_uint64", + UnsignedLong.class, + UnsignedLong.class, + RuntimeHelpers::uint64Divide); + } else { + return CelFunctionBinding.from( + "divide_uint64", + Long.class, + Long.class, + (Long x, Long y) -> + RuntimeHelpers.uint64Divide(x, y, bindingHelper.celOptions)); + } + }), + MODULO_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "modulo_int64", + Long.class, + Long.class, + (Long x, Long y) -> { + try { + return x % y; + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + MODULO_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "modulo_uint64", + UnsignedLong.class, + UnsignedLong.class, + RuntimeHelpers::uint64Mod); + } else { + return CelFunctionBinding.from( + "modulo_uint64", + Long.class, + Long.class, + (Long x, Long y) -> RuntimeHelpers.uint64Mod(x, y, bindingHelper.celOptions)); + } + }), + NEGATE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "negate_int64", + Long.class, + (Long x) -> { + try { + return RuntimeHelpers.int64Negate(x, bindingHelper.celOptions); + } catch (ArithmeticException e) { + throw new CelEvaluationException( + e.getMessage(), e, getArithmeticErrorCode(e)); + } + })), + NEGATE_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from("negate_double", Double.class, (Double x) -> -x)); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Arithmetic(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for indexing a list or a map. */ + public enum Index implements StandardOverload { + INDEX_LIST( + (bindingHelper) -> + CelFunctionBinding.from( + "index_list", List.class, Number.class, RuntimeHelpers::indexList)), + INDEX_MAP( + (bindingHelper) -> + CelFunctionBinding.from( + "index_map", + Map.class, + Object.class, + (Map map, Object key) -> + bindingHelper.runtimeEquality.indexMap( + map, key, bindingHelper.celOptions))); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Index(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for retrieving the size of a literal or a collection. */ + public enum Size implements StandardOverload { + SIZE_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "size_bytes", ByteString.class, (ByteString bytes) -> (long) bytes.size())), + BYTES_SIZE( + (bindingHelper) -> + CelFunctionBinding.from( + "bytes_size", ByteString.class, (ByteString bytes) -> (long) bytes.size())), + SIZE_LIST( + (bindingHelper) -> + CelFunctionBinding.from( + "size_list", List.class, (List list1) -> (long) list1.size())), + LIST_SIZE( + (bindingHelper) -> + CelFunctionBinding.from( + "list_size", List.class, (List list1) -> (long) list1.size())), + SIZE_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "size_string", + String.class, + (String s) -> (long) s.codePointCount(0, s.length()))), + STRING_SIZE( + (bindingHelper) -> + CelFunctionBinding.from( + "string_size", + String.class, + (String s) -> (long) s.codePointCount(0, s.length()))), + SIZE_MAP( + (bindingHelper) -> + CelFunctionBinding.from("size_map", Map.class, (Map map1) -> (long) map1.size())), + MAP_SIZE( + (bindingHelper) -> + CelFunctionBinding.from("map_size", Map.class, (Map map1) -> (long) map1.size())); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Size(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for performing type conversions. */ + public enum Conversions implements StandardOverload { + // Bool conversions + BOOL_TO_BOOL( + (bindingHelper) -> + CelFunctionBinding.from("bool_to_bool", Boolean.class, (Boolean x) -> x)), + STRING_TO_BOOL( + (bindingHelper) -> + CelFunctionBinding.from( + "string_to_bool", + String.class, + (String str) -> { + 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 CelEvaluationException( + String.format( + "Type conversion error from 'string' to 'bool': [%s]", str), + CelErrorCode.BAD_FORMAT); + } + })), + // Int conversions + INT64_TO_INT64( + (bindingHelper) -> + CelFunctionBinding.from("int64_to_int64", Long.class, (Long x) -> x)), + DOUBLE_TO_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "double_to_int64", + Double.class, + (Double arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap()) { + return RuntimeHelpers.doubleToLongChecked(arg) + .orElseThrow( + () -> + new CelEvaluationException( + "double is out of range for int", + CelErrorCode.NUMERIC_OVERFLOW)); + } + return arg.longValue(); + })), + STRING_TO_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "string_to_int64", + String.class, + (String arg) -> { + try { + return Long.parseLong(arg); + } catch (NumberFormatException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + })), + TIMESTAMP_TO_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_int64", Timestamp.class, Timestamps::toSeconds)), + UINT64_TO_INT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "uint64_to_int64", + UnsignedLong.class, + (UnsignedLong arg) -> { + if (arg.compareTo(UnsignedLong.valueOf(Long.MAX_VALUE)) > 0) { + throw new CelEvaluationException( + "unsigned out of int range", CelErrorCode.NUMERIC_OVERFLOW); + } + return arg.longValue(); + }); + } else { + return CelFunctionBinding.from( + "uint64_to_int64", + Long.class, + (Long arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap() && arg < 0) { + throw new CelEvaluationException( + "unsigned out of int range", CelErrorCode.NUMERIC_OVERFLOW); + } + return arg; + }); + } + }), + // Uint conversions + UINT64_TO_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "uint64_to_uint64", UnsignedLong.class, (UnsignedLong x) -> x); + } else { + return CelFunctionBinding.from("uint64_to_uint64", Long.class, (Long x) -> x); + } + }), + INT64_TO_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "int64_to_uint64", + Long.class, + (Long arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap() && arg < 0) { + throw new CelEvaluationException( + "int out of uint range", CelErrorCode.NUMERIC_OVERFLOW); + } + return UnsignedLong.valueOf(arg); + }); + } else { + return CelFunctionBinding.from( + "int64_to_uint64", + Long.class, + (Long arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap() && arg < 0) { + throw new CelEvaluationException( + "int out of uint range", CelErrorCode.NUMERIC_OVERFLOW); + } + return arg; + }); + } + }), + DOUBLE_TO_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "double_to_uint64", + Double.class, + (Double arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap()) { + return RuntimeHelpers.doubleToUnsignedChecked(arg) + .orElseThrow( + () -> + new CelEvaluationException( + "double out of uint range", CelErrorCode.NUMERIC_OVERFLOW)); + } + return UnsignedLong.valueOf(BigDecimal.valueOf(arg).toBigInteger()); + }); + } else { + return CelFunctionBinding.from( + "double_to_uint64", + Double.class, + (Double arg) -> { + if (bindingHelper.celOptions.errorOnIntWrap()) { + return RuntimeHelpers.doubleToUnsignedChecked(arg) + .map(UnsignedLong::longValue) + .orElseThrow( + () -> + new CelEvaluationException( + "double out of uint range", CelErrorCode.NUMERIC_OVERFLOW)); + } + return arg.longValue(); + }); + } + }), + STRING_TO_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "string_to_uint64", + String.class, + (String arg) -> { + try { + return UnsignedLong.valueOf(arg); + } catch (NumberFormatException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + }); + } else { + return CelFunctionBinding.from( + "string_to_uint64", + String.class, + (String arg) -> { + try { + return UnsignedLongs.parseUnsignedLong(arg); + } catch (NumberFormatException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + }); + } + }), + // Double conversions + DOUBLE_TO_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from("double_to_double", Double.class, (Double x) -> x)), + INT64_TO_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from("int64_to_double", Long.class, Long::doubleValue)), + STRING_TO_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "string_to_double", + String.class, + (String arg) -> { + try { + return Double.parseDouble(arg); + } catch (NumberFormatException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + })), + UINT64_TO_DOUBLE( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "uint64_to_double", UnsignedLong.class, UnsignedLong::doubleValue); + } else { + return CelFunctionBinding.from( + "uint64_to_double", + Long.class, + (Long arg) -> UnsignedLong.fromLongBits(arg).doubleValue()); + } + }), + // String conversions + STRING_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from("string_to_string", String.class, (String x) -> x)), + INT64_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from("int64_to_string", Long.class, Object::toString)), + DOUBLE_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from("double_to_string", Double.class, Object::toString)), + BYTES_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "bytes_to_string", ByteString.class, ByteString::toStringUtf8)), + TIMESTAMP_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_string", Timestamp.class, Timestamps::toString)), + DURATION_TO_STRING( + (bindingHelper) -> + CelFunctionBinding.from("duration_to_string", Duration.class, Durations::toString)), + UINT64_TO_STRING( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "uint64_to_string", UnsignedLong.class, UnsignedLong::toString); + } else { + return CelFunctionBinding.from( + "uint64_to_string", Long.class, UnsignedLongs::toString); + } + }), + + // Bytes conversions + BYTES_TO_BYTES( + (bindingHelper) -> + CelFunctionBinding.from("bytes_to_bytes", ByteString.class, (ByteString x) -> x)), + STRING_TO_BYTES( + (bindingHelper) -> + CelFunctionBinding.from("string_to_bytes", String.class, ByteString::copyFromUtf8)), + // Duration conversions + DURATION_TO_DURATION( + (bindingHelper) -> + CelFunctionBinding.from("duration_to_duration", Duration.class, (Duration x) -> x)), + STRING_TO_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "string_to_duration", + String.class, + (String d) -> { + try { + return RuntimeHelpers.createDurationFromString(d); + } catch (IllegalArgumentException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + })), + + STRING_TO_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "string_to_timestamp", + String.class, + (String ts) -> { + try { + return Timestamps.parse(ts); + } catch (ParseException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.BAD_FORMAT); + } + })), + TIMESTAMP_TO_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_timestamp", Timestamp.class, (Timestamp x) -> x)), + INT64_TO_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from("int64_to_timestamp", Long.class, Timestamps::fromSeconds)), + TO_DYN( + (bindingHelper) -> + CelFunctionBinding.from("to_dyn", Object.class, (Object arg) -> arg)); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Conversions(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** + * Overloads for functions performing string matching, such as regular expressions or contains + * check. + */ + public enum StringMatchers implements StandardOverload { + MATCHES( + (bindingHelper) -> + CelFunctionBinding.from( + "matches", + String.class, + String.class, + (String string, String regexp) -> { + try { + return RuntimeHelpers.matches(string, regexp, bindingHelper.celOptions); + } catch (PatternSyntaxException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.INVALID_ARGUMENT); + } + })), + // Duplicate receiver-style matches overload. + MATCHES_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "matches_string", + String.class, + String.class, + (String string, String regexp) -> { + try { + return RuntimeHelpers.matches(string, regexp, bindingHelper.celOptions); + } catch (PatternSyntaxException e) { + throw new CelEvaluationException( + e.getMessage(), e, CelErrorCode.INVALID_ARGUMENT); + } + })), + CONTAINS_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "contains_string", String.class, String.class, String::contains)), + ENDS_WITH_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "ends_with_string", String.class, String.class, String::endsWith)), + STARTS_WITH_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "starts_with_string", String.class, String.class, String::startsWith)); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + StringMatchers(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for logical operators that return a bool as a result. */ + public enum BooleanOperator implements StandardOverload { + LOGICAL_NOT( + (bindingHelper) -> + CelFunctionBinding.from("logical_not", Boolean.class, (Boolean x) -> !x)); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + BooleanOperator(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for functions performing date/time operations. */ + public enum DateTime implements StandardOverload { + TIMESTAMP_TO_YEAR( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_year", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getYear())), + TIMESTAMP_TO_YEAR_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_year_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getYear())), + TIMESTAMP_TO_MONTH( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_month", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMonthValue() - 1)), + TIMESTAMP_TO_MONTH_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_month_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> + (long) newLocalDateTime(ts, tz).getMonthValue() - 1)), + TIMESTAMP_TO_DAY_OF_YEAR( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_year", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfYear() - 1)), + TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_year_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> + (long) newLocalDateTime(ts, tz).getDayOfYear() - 1)), + TIMESTAMP_TO_DAY_OF_MONTH( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_month", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth() - 1)), + TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_month_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> + (long) newLocalDateTime(ts, tz).getDayOfMonth() - 1)), + + TIMESTAMP_TO_DAY_OF_MONTH_1_BASED( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_month_1_based", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getDayOfMonth())), + TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_month_1_based_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getDayOfMonth())), + + TIMESTAMP_TO_DAY_OF_WEEK( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_week", + Timestamp.class, + (Timestamp ts) -> { + // CEL treats Sunday as day 0, but Java.time treats it as day 7. + DayOfWeek dayOfWeek = newLocalDateTime(ts, UTC).getDayOfWeek(); + return (long) dayOfWeek.getValue() % 7; + })), + TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_day_of_week_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> { + // CEL treats Sunday as day 0, but Java.time treats it as day 7. + DayOfWeek dayOfWeek = newLocalDateTime(ts, tz).getDayOfWeek(); + return (long) dayOfWeek.getValue() % 7; + })), + TIMESTAMP_TO_HOURS( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_hours", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getHour())), + TIMESTAMP_TO_HOURS_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_hours_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getHour())), + TIMESTAMP_TO_MINUTES( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_minutes", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getMinute())), + TIMESTAMP_TO_MINUTES_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_minutes_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getMinute())), + TIMESTAMP_TO_SECONDS( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_seconds", + Timestamp.class, + (Timestamp ts) -> (long) newLocalDateTime(ts, UTC).getSecond())), + TIMESTAMP_TO_SECONDS_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_seconds_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> (long) newLocalDateTime(ts, tz).getSecond())), + // We specifically need to only access nanos-of-second field for + // timestamp_to_milliseconds overload + @SuppressWarnings("JavaLocalDateTimeGetNano") + TIMESTAMP_TO_MILLISECONDS( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_milliseconds", + Timestamp.class, + (Timestamp ts) -> (long) (newLocalDateTime(ts, UTC).getNano() / 1e+6))), + + @SuppressWarnings("JavaLocalDateTimeGetNano") + TIMESTAMP_TO_MILLISECONDS_WITH_TZ( + (bindingHelper) -> + CelFunctionBinding.from( + "timestamp_to_milliseconds_with_tz", + Timestamp.class, + String.class, + (Timestamp ts, String tz) -> + (long) (newLocalDateTime(ts, tz).getNano() / 1e+6))), + DURATION_TO_HOURS( + (bindingHelper) -> + CelFunctionBinding.from("duration_to_hours", Duration.class, Durations::toHours)), + DURATION_TO_MINUTES( + (bindingHelper) -> + CelFunctionBinding.from( + "duration_to_minutes", Duration.class, Durations::toMinutes)), + DURATION_TO_SECONDS( + (bindingHelper) -> + CelFunctionBinding.from( + "duration_to_seconds", Duration.class, Durations::toSeconds)), + DURATION_TO_MILLISECONDS( + (bindingHelper) -> + CelFunctionBinding.from( + "duration_to_milliseconds", + Duration.class, + (Duration arg) -> + Durations.toMillis(arg) % java.time.Duration.ofSeconds(1).toMillis())); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + DateTime(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + /** Overloads for performing numeric comparisons. */ + public enum Comparison implements StandardOverload { + LESS_BOOL( + (bindingHelper) -> + CelFunctionBinding.from( + "less_bool", Boolean.class, Boolean.class, (Boolean x, Boolean y) -> !x && y), + false), + LESS_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_int64", Long.class, Long.class, (Long x, Long y) -> x < y), + false), + LESS_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "less_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> RuntimeHelpers.uint64CompareTo(x, y) < 0); + } else { + return CelFunctionBinding.from( + "less_uint64", + Long.class, + Long.class, + (Long x, Long y) -> + RuntimeHelpers.uint64CompareTo(x, y, bindingHelper.celOptions) < 0); + } + }, + false), + LESS_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "less_bytes", + ByteString.class, + ByteString.class, + (ByteString x, ByteString y) -> + ByteString.unsignedLexicographicalComparator().compare(x, y) < 0), + false), + LESS_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_double", Double.class, Double.class, (Double x, Double y) -> x < y), + false), + LESS_DOUBLE_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_double_uint64", + Double.class, + UnsignedLong.class, + (Double x, UnsignedLong y) -> + ComparisonFunctions.compareDoubleUint(x, y) == -1), + true), + LESS_INT64_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_int64_uint64", + Long.class, + UnsignedLong.class, + (Long x, UnsignedLong y) -> ComparisonFunctions.compareIntUint(x, y) == -1), + true), + LESS_UINT64_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_uint64_int64", + UnsignedLong.class, + Long.class, + (UnsignedLong x, Long y) -> ComparisonFunctions.compareUintInt(x, y) == -1), + true), + LESS_INT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_int64_double", + Long.class, + Double.class, + (Long x, Double y) -> ComparisonFunctions.compareIntDouble(x, y) == -1), + true), + LESS_DOUBLE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_double_int64", + Double.class, + Long.class, + (Double x, Long y) -> ComparisonFunctions.compareDoubleInt(x, y) == -1), + true), + LESS_UINT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_uint64_double", + UnsignedLong.class, + Double.class, + (UnsignedLong x, Double y) -> + ComparisonFunctions.compareUintDouble(x, y) == -1), + true), + LESS_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "less_duration", + Duration.class, + Duration.class, + (Duration x, Duration y) -> Durations.compare(x, y) < 0), + false), + LESS_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "less_string", + String.class, + String.class, + (String x, String y) -> x.compareTo(y) < 0), + false), + LESS_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "less_timestamp", + Timestamp.class, + Timestamp.class, + (Timestamp x, Timestamp y) -> Timestamps.compare(x, y) < 0), + false), + LESS_EQUALS_BOOL( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_bool", + Boolean.class, + Boolean.class, + (Boolean x, Boolean y) -> !x || y), + false), + LESS_EQUALS_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_bytes", + ByteString.class, + ByteString.class, + (ByteString x, ByteString y) -> + ByteString.unsignedLexicographicalComparator().compare(x, y) <= 0), + false), + LESS_EQUALS_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_double", + Double.class, + Double.class, + (Double x, Double y) -> x <= y), + false), + LESS_EQUALS_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_duration", + Duration.class, + Duration.class, + (Duration x, Duration y) -> Durations.compare(x, y) <= 0), + false), + LESS_EQUALS_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_int64", Long.class, Long.class, (Long x, Long y) -> x <= y), + false), + LESS_EQUALS_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_string", + String.class, + String.class, + (String x, String y) -> x.compareTo(y) <= 0), + false), + LESS_EQUALS_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_timestamp", + Timestamp.class, + Timestamp.class, + (Timestamp x, Timestamp y) -> Timestamps.compare(x, y) <= 0), + false), + LESS_EQUALS_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "less_equals_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> RuntimeHelpers.uint64CompareTo(x, y) <= 0); + } else { + return CelFunctionBinding.from( + "less_equals_uint64", + Long.class, + Long.class, + (Long x, Long y) -> + RuntimeHelpers.uint64CompareTo(x, y, bindingHelper.celOptions) <= 0); + } + }, + false), + LESS_EQUALS_INT64_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_int64_uint64", + Long.class, + UnsignedLong.class, + (Long x, UnsignedLong y) -> ComparisonFunctions.compareIntUint(x, y) <= 0), + true), + LESS_EQUALS_UINT64_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_uint64_int64", + UnsignedLong.class, + Long.class, + (UnsignedLong x, Long y) -> ComparisonFunctions.compareUintInt(x, y) <= 0), + true), + LESS_EQUALS_INT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_int64_double", + Long.class, + Double.class, + (Long x, Double y) -> ComparisonFunctions.compareIntDouble(x, y) <= 0), + true), + LESS_EQUALS_DOUBLE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_double_int64", + Double.class, + Long.class, + (Double x, Long y) -> ComparisonFunctions.compareDoubleInt(x, y) <= 0), + true), + LESS_EQUALS_UINT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_uint64_double", + UnsignedLong.class, + Double.class, + (UnsignedLong x, Double y) -> ComparisonFunctions.compareUintDouble(x, y) <= 0), + true), + LESS_EQUALS_DOUBLE_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "less_equals_double_uint64", + Double.class, + UnsignedLong.class, + (Double x, UnsignedLong y) -> ComparisonFunctions.compareDoubleUint(x, y) <= 0), + true), + GREATER_BOOL( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_bool", + Boolean.class, + Boolean.class, + (Boolean x, Boolean y) -> x && !y), + false), + GREATER_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_bytes", + ByteString.class, + ByteString.class, + (ByteString x, ByteString y) -> + ByteString.unsignedLexicographicalComparator().compare(x, y) > 0), + false), + GREATER_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_double", Double.class, Double.class, (Double x, Double y) -> x > y), + false), + GREATER_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_duration", + Duration.class, + Duration.class, + (Duration x, Duration y) -> Durations.compare(x, y) > 0), + false), + GREATER_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_int64", Long.class, Long.class, (Long x, Long y) -> x > y), + false), + GREATER_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_string", + String.class, + String.class, + (String x, String y) -> x.compareTo(y) > 0), + false), + GREATER_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_timestamp", + Timestamp.class, + Timestamp.class, + (Timestamp x, Timestamp y) -> Timestamps.compare(x, y) > 0), + false), + GREATER_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "greater_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> RuntimeHelpers.uint64CompareTo(x, y) > 0); + } else { + return CelFunctionBinding.from( + "greater_uint64", + Long.class, + Long.class, + (Long x, Long y) -> + RuntimeHelpers.uint64CompareTo(x, y, bindingHelper.celOptions) > 0); + } + }, + false), + GREATER_INT64_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_int64_uint64", + Long.class, + UnsignedLong.class, + (Long x, UnsignedLong y) -> ComparisonFunctions.compareIntUint(x, y) == 1), + true), + GREATER_UINT64_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_uint64_int64", + UnsignedLong.class, + Long.class, + (UnsignedLong x, Long y) -> ComparisonFunctions.compareUintInt(x, y) == 1), + true), + GREATER_INT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_int64_double", + Long.class, + Double.class, + (Long x, Double y) -> ComparisonFunctions.compareIntDouble(x, y) == 1), + true), + GREATER_DOUBLE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_double_int64", + Double.class, + Long.class, + (Double x, Long y) -> ComparisonFunctions.compareDoubleInt(x, y) == 1), + true), + GREATER_UINT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_uint64_double", + UnsignedLong.class, + Double.class, + (UnsignedLong x, Double y) -> ComparisonFunctions.compareUintDouble(x, y) == 1), + true), + GREATER_DOUBLE_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_double_uint64", + Double.class, + UnsignedLong.class, + (Double x, UnsignedLong y) -> ComparisonFunctions.compareDoubleUint(x, y) == 1), + true), + GREATER_EQUALS_BOOL( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_bool", + Boolean.class, + Boolean.class, + (Boolean x, Boolean y) -> x || !y), + false), + GREATER_EQUALS_BYTES( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_bytes", + ByteString.class, + ByteString.class, + (ByteString x, ByteString y) -> + ByteString.unsignedLexicographicalComparator().compare(x, y) >= 0), + false), + GREATER_EQUALS_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_double", + Double.class, + Double.class, + (Double x, Double y) -> x >= y), + false), + GREATER_EQUALS_DURATION( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_duration", + Duration.class, + Duration.class, + (Duration x, Duration y) -> Durations.compare(x, y) >= 0), + false), + GREATER_EQUALS_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_int64", Long.class, Long.class, (Long x, Long y) -> x >= y), + false), + GREATER_EQUALS_STRING( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_string", + String.class, + String.class, + (String x, String y) -> x.compareTo(y) >= 0), + false), + GREATER_EQUALS_TIMESTAMP( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_timestamp", + Timestamp.class, + Timestamp.class, + (Timestamp x, Timestamp y) -> Timestamps.compare(x, y) >= 0), + false), + GREATER_EQUALS_UINT64( + (bindingHelper) -> { + if (bindingHelper.celOptions.enableUnsignedLongs()) { + return CelFunctionBinding.from( + "greater_equals_uint64", + UnsignedLong.class, + UnsignedLong.class, + (UnsignedLong x, UnsignedLong y) -> RuntimeHelpers.uint64CompareTo(x, y) >= 0); + } else { + return CelFunctionBinding.from( + "greater_equals_uint64", + Long.class, + Long.class, + (Long x, Long y) -> + RuntimeHelpers.uint64CompareTo(x, y, bindingHelper.celOptions) >= 0); + } + }, + false), + GREATER_EQUALS_INT64_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_int64_uint64", + Long.class, + UnsignedLong.class, + (Long x, UnsignedLong y) -> ComparisonFunctions.compareIntUint(x, y) >= 0), + true), + GREATER_EQUALS_UINT64_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_uint64_int64", + UnsignedLong.class, + Long.class, + (UnsignedLong x, Long y) -> ComparisonFunctions.compareUintInt(x, y) >= 0), + true), + GREATER_EQUALS_INT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_int64_double", + Long.class, + Double.class, + (Long x, Double y) -> ComparisonFunctions.compareIntDouble(x, y) >= 0), + true), + GREATER_EQUALS_DOUBLE_INT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_double_int64", + Double.class, + Long.class, + (Double x, Long y) -> ComparisonFunctions.compareDoubleInt(x, y) >= 0), + true), + GREATER_EQUALS_UINT64_DOUBLE( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_uint64_double", + UnsignedLong.class, + Double.class, + (UnsignedLong x, Double y) -> ComparisonFunctions.compareUintDouble(x, y) >= 0), + true), + GREATER_EQUALS_DOUBLE_UINT64( + (bindingHelper) -> + CelFunctionBinding.from( + "greater_equals_double_uint64", + Double.class, + UnsignedLong.class, + (Double x, UnsignedLong y) -> ComparisonFunctions.compareDoubleUint(x, y) >= 0), + true); + + private final FunctionBindingCreator bindingCreator; + private final boolean isHeterogeneousComparison; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + Comparison(FunctionBindingCreator bindingCreator, boolean isHeterogeneousComparison) { + this.bindingCreator = bindingCreator; + this.isHeterogeneousComparison = isHeterogeneousComparison; + } + + public boolean isHeterogeneousComparison() { + return isHeterogeneousComparison; + } + } + + /** Overloads for optional values. */ + public enum OptionalValue implements StandardOverload { + SELECT_OPTIONAL_FIELD( + (bindingHelper) -> + CelFunctionBinding.from( + "select_optional_field", // This only handles map selection. Proto selection is + // special cased inside the interpreter. + Map.class, + String.class, + (Map map, String key) -> + bindingHelper.runtimeEquality.findInMap( + map, key, bindingHelper.celOptions))), + MAP_OPTINDEX_OPTIONAL_VALUE( + (bindingHelper) -> + CelFunctionBinding.from( + "map_optindex_optional_value", + Map.class, + Object.class, + (Map map, Object key) -> + bindingHelper.runtimeEquality.findInMap( + map, key, bindingHelper.celOptions))), + OPTIONAL_MAP_OPTINDEX_OPTIONAL_VALUE( + (bindingHelper) -> + CelFunctionBinding.from( + "optional_map_optindex_optional_value", + Optional.class, + Object.class, + (Optional optionalMap, Object key) -> + indexOptionalMap( + optionalMap, + key, + bindingHelper.celOptions, + bindingHelper.runtimeEquality))), + OPTIONAL_MAP_INDEX_VALUE( + (bindingHelper) -> + CelFunctionBinding.from( + "optional_map_index_value", + Optional.class, + Object.class, + (Optional optionalMap, Object key) -> + indexOptionalMap( + optionalMap, + key, + bindingHelper.celOptions, + bindingHelper.runtimeEquality))), + OPTIONAL_LIST_INDEX_INT( + (bindingHelper) -> + CelFunctionBinding.from( + "optional_list_index_int", + Optional.class, + Long.class, + CelStandardFunctions::indexOptionalList)), + LIST_OPTINDEX_OPTIONAL_INT( + (bindingHelper) -> + CelFunctionBinding.from( + "list_optindex_optional_int", + List.class, + Long.class, + (List list, Long index) -> { + int castIndex = Ints.checkedCast(index); + if (castIndex < 0 || castIndex >= list.size()) { + return Optional.empty(); + } + return Optional.of(list.get(castIndex)); + })), + OPTIONAL_LIST_OPTINDEX_OPTIONAL_INT( + (bindingHelper) -> + CelFunctionBinding.from( + "optional_list_optindex_optional_int", + Optional.class, + Long.class, + CelStandardFunctions::indexOptionalList)); + + private final FunctionBindingCreator bindingCreator; + + @Override + public CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper) { + return bindingCreator.create(functionBindingHelper); + } + + OptionalValue(FunctionBindingCreator bindingCreator) { + this.bindingCreator = bindingCreator; + } + } + + private Overload() {} + } + + private final ImmutableSet standardOverloads; + + StandardFunction(StandardOverload... overloads) { + this.standardOverloads = ImmutableSet.copyOf(overloads); + } + + @VisibleForTesting + ImmutableSet getOverloads() { + return standardOverloads; + } + } + + @VisibleForTesting + ImmutableSet getOverloads() { + return standardOverloads; + } + + public ImmutableSet newFunctionBindings( + DynamicProto dynamicProto, CelOptions celOptions) { + FunctionBindingHelper helper = new FunctionBindingHelper(celOptions, dynamicProto); + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (StandardOverload overload : standardOverloads) { + builder.add(overload.newFunctionBinding(helper)); + } + + return builder.build(); + } + + /** General interface for defining a standard function overload. */ + @Immutable + public interface StandardOverload { + CelFunctionBinding newFunctionBinding(FunctionBindingHelper functionBindingHelper); + } + + /** Builder for constructing the set of standard function/identifiers. */ + public static final class Builder { + private ImmutableSet includeFunctions; + private ImmutableSet excludeFunctions; + + private FunctionFilter functionFilter; + + private Builder() { + this.includeFunctions = ImmutableSet.of(); + this.excludeFunctions = ImmutableSet.of(); + } + + @CanIgnoreReturnValue + public Builder excludeFunctions(StandardFunction... functions) { + return excludeFunctions(ImmutableSet.copyOf(functions)); + } + + @CanIgnoreReturnValue + public Builder excludeFunctions(Iterable functions) { + this.excludeFunctions = checkNotNull(ImmutableSet.copyOf(functions)); + return this; + } + + @CanIgnoreReturnValue + public Builder includeFunctions(StandardFunction... functions) { + return includeFunctions(ImmutableSet.copyOf(functions)); + } + + @CanIgnoreReturnValue + public Builder includeFunctions(Iterable functions) { + this.includeFunctions = checkNotNull(ImmutableSet.copyOf(functions)); + return this; + } + + @CanIgnoreReturnValue + public Builder filterFunctions(FunctionFilter functionFilter) { + this.functionFilter = functionFilter; + return this; + } + + private static void assertOneSettingIsSet( + boolean a, boolean b, boolean c, String errorMessage) { + int count = 0; + if (a) { + count++; + } + if (b) { + count++; + } + if (c) { + count++; + } + + if (count > 1) { + throw new IllegalArgumentException(errorMessage); + } + } + + public CelStandardFunctions build() { + boolean hasIncludeFunctions = !this.includeFunctions.isEmpty(); + boolean hasExcludeFunctions = !this.excludeFunctions.isEmpty(); + boolean hasFilterFunction = this.functionFilter != null; + assertOneSettingIsSet( + hasIncludeFunctions, + hasExcludeFunctions, + hasFilterFunction, + "You may only populate one of the following builder methods: includeFunctions," + + " excludeFunctions or filterFunctions"); + + ImmutableSet.Builder standardOverloadBuilder = ImmutableSet.builder(); + for (StandardFunction standardFunction : StandardFunction.values()) { + if (hasIncludeFunctions) { + if (this.includeFunctions.contains(standardFunction)) { + standardOverloadBuilder.addAll(standardFunction.standardOverloads); + } + continue; + } + if (hasExcludeFunctions) { + if (!this.excludeFunctions.contains(standardFunction)) { + standardOverloadBuilder.addAll(standardFunction.standardOverloads); + } + continue; + } + if (hasFilterFunction) { + ImmutableSet.Builder filteredOverloadsBuilder = ImmutableSet.builder(); + for (StandardOverload standardOverload : standardFunction.standardOverloads) { + boolean includeOverload = functionFilter.include(standardFunction, standardOverload); + if (includeOverload) { + standardOverloadBuilder.add(standardOverload); + } + } + + ImmutableSet filteredOverloads = filteredOverloadsBuilder.build(); + if (!filteredOverloads.isEmpty()) { + standardOverloadBuilder.addAll(filteredOverloads); + } + + continue; + } + + standardOverloadBuilder.addAll(standardFunction.standardOverloads); + } + + return new CelStandardFunctions(standardOverloadBuilder.build()); + } + + /** + * Functional interface for filtering standard functions. Returning true in the callback will + * include the function in the environment. + */ + @FunctionalInterface + public interface FunctionFilter { + boolean include(StandardFunction standardFunction, StandardOverload standardOverload); + } + } + + /** Creates a new builder to configure CelStandardFunctions. */ + public static Builder newBuilder() { + return new Builder(); + } + + @Immutable + private static final class FunctionBindingHelper { + private final CelOptions celOptions; + private final RuntimeEquality runtimeEquality; + + private FunctionBindingHelper(CelOptions celOptions, DynamicProto dynamicProto) { + this.celOptions = celOptions; + this.runtimeEquality = new RuntimeEquality(dynamicProto); + } + } + + @FunctionalInterface + @Immutable + private interface FunctionBindingCreator { + CelFunctionBinding create(FunctionBindingHelper helper); + } + + private static CelErrorCode getArithmeticErrorCode(ArithmeticException e) { + String exceptionMessage = e.getMessage(); + // The two known cases for an arithmetic exception is divide by zero and overflow. + if (exceptionMessage.equals("/ by zero")) { + return CelErrorCode.DIVIDE_BY_ZERO; + } + return CelErrorCode.NUMERIC_OVERFLOW; + } + + /** + * Constructs a new {@link LocalDateTime} instance + * + * @param ts Timestamp protobuf object + * @param tz Timezone based on the CEL specification. This is either the canonical name from tz + * database or a standard offset represented in (+/-)HH:MM. Few valid examples are: + *

      + *
    • UTC + *
    • America/Los_Angeles + *
    • -09:30 or -9:30 (Leading zeroes can be omitted though not allowed by spec) + *
    + * + * @return If an Invalid timezone is supplied. + */ + private static LocalDateTime newLocalDateTime(Timestamp ts, String tz) + throws CelEvaluationException { + return Instant.ofEpochSecond(ts.getSeconds(), ts.getNanos()) + .atZone(timeZone(tz)) + .toLocalDateTime(); + } + + /** + * Get the DateTimeZone Instance. + * + * @param tz the ID of the datetime zone + * @return the ZoneId object + * @throws CelEvaluationException if there is an invalid timezone + */ + private static ZoneId timeZone(String tz) throws CelEvaluationException { + try { + return ZoneId.of(tz); + } catch (DateTimeException e) { + // If timezone is not a string name (for example, 'US/Central'), it should be a numerical + // offset from UTC in the format [+/-]HH:MM. + try { + int ind = tz.indexOf(":"); + if (ind == -1) { + throw new CelEvaluationException(e.getMessage()); + } + + int hourOffset = Integer.parseInt(tz.substring(0, ind)); + int minOffset = Integer.parseInt(tz.substring(ind + 1)); + // Ensures that the offset are properly formatted in [+/-]HH:MM to conform with + // ZoneOffset's format requirements. + // Example: "-9:30" -> "-09:30" and "9:30" -> "+09:30" + String formattedOffset = + ((hourOffset < 0) ? "-" : "+") + + String.format("%02d:%02d", Math.abs(hourOffset), minOffset); + + return ZoneId.of(formattedOffset); + + } catch (DateTimeException e2) { + throw new CelEvaluationException(e2.getMessage()); + } + } + } + + private static Object indexOptionalMap( + Optional optionalMap, Object key, CelOptions options, RuntimeEquality runtimeEquality) { + if (!optionalMap.isPresent()) { + return Optional.empty(); + } + + Map map = (Map) optionalMap.get(); + + return runtimeEquality.findInMap(map, key, options); + } + + private static Object indexOptionalList(Optional optionalList, long index) { + if (!optionalList.isPresent()) { + return Optional.empty(); + } + List list = (List) optionalList.get(); + int castIndex = Ints.checkedCast(index); + if (castIndex < 0 || castIndex >= list.size()) { + return Optional.empty(); + } + return Optional.of(list.get(castIndex)); + } + + private CelStandardFunctions(ImmutableSet standardOverloads) { + this.standardOverloads = standardOverloads; + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/CelTypeResolver.java b/runtime/src/main/java/dev/cel/runtime/CelTypeResolver.java new file mode 100644 index 000000000..93e2d77de --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelTypeResolver.java @@ -0,0 +1,155 @@ +// 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.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +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.MessageOrBuilder; +import com.google.protobuf.NullValue; +import com.google.protobuf.Timestamp; +import dev.cel.common.types.CelType; +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.StructType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.common.types.TypeType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * {@code CelTypeResolver} resolves incoming {@link CelType} into {@link TypeType}., either as part + * of a type call (type('foo'), type(1), etc.) or as a type literal (type, int, string, etc.) + */ +@Immutable +final class CelTypeResolver { + + // Sentinel runtime value representing the special "type" ident. This ensures following to be + // true: type == type(string) && type == type(type("foo")) + private static final TypeType RUNTIME_TYPE_TYPE = TypeType.create(SimpleType.DYN); + + private static final ImmutableMap, TypeType> COMMON_TYPES = + ImmutableMap., TypeType>builder() + .put(Boolean.class, TypeType.create(SimpleType.BOOL)) + .put(Double.class, TypeType.create(SimpleType.DOUBLE)) + .put(Long.class, TypeType.create(SimpleType.INT)) + .put(UnsignedLong.class, TypeType.create(SimpleType.UINT)) + .put(String.class, TypeType.create(SimpleType.STRING)) + .put(NullValue.class, TypeType.create(SimpleType.NULL_TYPE)) + .put(Duration.class, TypeType.create(SimpleType.DURATION)) + .put(Timestamp.class, TypeType.create(SimpleType.TIMESTAMP)) + .put(ArrayList.class, TypeType.create(ListType.create(SimpleType.DYN))) + .put(ImmutableList.class, TypeType.create(ListType.create(SimpleType.DYN))) + .put(HashMap.class, TypeType.create(MapType.create(SimpleType.DYN, SimpleType.DYN))) + .put(ImmutableMap.class, TypeType.create(MapType.create(SimpleType.DYN, SimpleType.DYN))) + .put(Optional.class, TypeType.create(OptionalType.create(SimpleType.DYN))) + .buildOrThrow(); + + private static final ImmutableMap, TypeType> EXTENDABLE_TYPES = + ImmutableMap., TypeType>builder() + .put(Collection.class, TypeType.create(ListType.create(SimpleType.DYN))) + .put(ByteString.class, TypeType.create(SimpleType.BYTES)) + .put(Map.class, TypeType.create(MapType.create(SimpleType.DYN, SimpleType.DYN))) + .buildOrThrow(); + + /** Adapt the type-checked {@link CelType} into a runtime type value {@link TypeType}. */ + static TypeType adaptType(CelType typeCheckedType) { + checkNotNull(typeCheckedType); + + switch (typeCheckedType.kind()) { + case TYPE: + CelType typeOfType = ((TypeType) typeCheckedType).type(); + switch (typeOfType.kind()) { + case STRUCT: + return TypeType.create(adaptStructType((StructType) typeOfType)); + default: + return (TypeType) typeCheckedType; + } + case UNSPECIFIED: + throw new IllegalArgumentException("Unsupported CelType kind: " + typeCheckedType.kind()); + default: + return TypeType.create(typeCheckedType); + } + } + + /** Resolve the CEL type of the {@code obj}. */ + static TypeType resolveObjectType(Object obj, CelType typeCheckedType) { + checkNotNull(obj); + if (obj instanceof TypeType) { + return RUNTIME_TYPE_TYPE; + } + + Class currentClass = obj.getClass(); + TypeType runtimeType = COMMON_TYPES.get(currentClass); + if (runtimeType != null) { + return runtimeType; + } + + if (obj instanceof MessageOrBuilder) { + MessageOrBuilder msg = (MessageOrBuilder) obj; + // TODO: Replace with CelLiteDescriptor + return TypeType.create(StructTypeReference.create(msg.getDescriptorForType().getFullName())); + } + + // Handle types that the client may have extended. + while (currentClass != null) { + runtimeType = EXTENDABLE_TYPES.get(currentClass); + if (runtimeType != null) { + return runtimeType; + } + + // Check interfaces + for (Class interfaceClass : currentClass.getInterfaces()) { + runtimeType = EXTENDABLE_TYPES.get(interfaceClass); + if (runtimeType != null) { + return runtimeType; + } + } + currentClass = currentClass.getSuperclass(); + } + + // This is an opaque type, or something CEL doesn't know about. + return (TypeType) typeCheckedType; + } + + private static CelType adaptStructType(StructType typeOfType) { + String structName = typeOfType.name(); + CelType newTypeOfType; + if (structName.equals(SimpleType.DURATION.name())) { + newTypeOfType = SimpleType.DURATION; + } else if (structName.equals(SimpleType.TIMESTAMP.name())) { + newTypeOfType = SimpleType.TIMESTAMP; + } else { + // Coerces ProtoMessageTypeProvider to be a struct type reference for accurate + // equality tests. + // In the future, we can plumb ProtoMessageTypeProvider through the runtime to retain + // ProtoMessageType here. + newTypeOfType = StructTypeReference.create(typeOfType.name()); + } + return newTypeOfType; + } + + private CelTypeResolver() {} +} diff --git a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java index 8cde13361..070e94cf0 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java +++ b/runtime/src/main/java/dev/cel/runtime/CelUnknownSet.java @@ -28,21 +28,50 @@ */ @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()); + } + + public static CelUnknownSet create(Long... unknownExprIds) { + return create(ImmutableSet.copyOf(unknownExprIds)); + } + + public static CelUnknownSet create(CelAttribute attribute, Iterable unknownExprIds) { + return create(ImmutableSet.of(attribute), 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/DefaultDispatcher.java b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java index cfc16bee7..fc0476840 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java @@ -14,24 +14,21 @@ package dev.cel.runtime; +import com.google.auto.value.AutoValue; 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.CelException; 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; import java.util.List; import java.util.Map; +import java.util.Optional; /** * Default implementation of {@link Dispatcher}. @@ -43,93 +40,22 @@ @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 + @Internal 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) { - DefaultDispatcher dispatcher = new DefaultDispatcher(); - if (enableStandardEnvironment) { - StandardFunctions.add(dispatcher, dynamicProto, celOptions); - } - return dispatcher; - } - - /** Internal representation of an overload. */ - @Immutable - private static final class Overload { - final ImmutableList> parameterTypes; - - /** See {@link Function}. */ - final Function function; - - private Overload(Class[] parameterTypes, Function function) { - this.parameterTypes = ImmutableList.copyOf(parameterTypes); - this.function = function; - } - - /** Determines whether this overload can handle the given arguments. */ - private boolean canHandle(Object[] arguments) { - if (parameterTypes.size() != arguments.length) { - return false; - } - for (int i = 0; i < parameterTypes.size(); i++) { - Class paramType = parameterTypes.get(i); - Object arg = arguments[i]; - if (arg == null) { - // null can be assigned to messages, maps, and to objects. - if (paramType != Object.class - && !MessageLite.class.isAssignableFrom(paramType) - && !Map.class.isAssignableFrom(paramType)) { - return false; - } - continue; - } - if (!paramType.isAssignableFrom(arg.getClass())) { - return false; - } - } - return true; - } + return new DefaultDispatcher(); } @GuardedBy("this") - private final Map overloads = new HashMap<>(); + private final Map overloads = new HashMap<>(); @Override @SuppressWarnings("unchecked") public synchronized void add( - String overloadId, Class argType, final UnaryFunction function) { + String overloadId, Class argType, final Registrar.UnaryFunction function) { overloads.put( - overloadId, new Overload(new Class[] {argType}, args -> function.apply((T) args[0]))); + overloadId, + ResolvedOverloadImpl.of( + overloadId, new Class[] {argType}, args -> function.apply((T) args[0]))); } @Override @@ -138,73 +64,63 @@ public synchronized void add( String overloadId, Class argType1, Class argType2, - final BinaryFunction function) { + final Registrar.BinaryFunction function) { overloads.put( overloadId, - new Overload( + ResolvedOverloadImpl.of( + overloadId, new Class[] {argType1, argType2}, args -> function.apply((T1) args[0], (T2) args[1]))); } @Override - public synchronized void add(String overloadId, List> argTypes, Function function) { - overloads.put(overloadId, new Overload(argTypes.toArray(new Class[0]), function)); + public synchronized void add( + String overloadId, List> argTypes, Registrar.Function function) { + overloads.put( + overloadId, + ResolvedOverloadImpl.of(overloadId, argTypes.toArray(new Class[0]), function)); + } + + @Override + public synchronized Optional findOverload( + String functionName, List overloadIds, Object[] args) throws CelException { + return DefaultDispatcher.findOverload(functionName, overloadIds, overloads, args); } - private static Object dispatch( - Metadata metadata, - long exprId, + /** Finds the overload that matches the given function name, overload IDs, and arguments. */ + public static Optional findOverload( String functionName, List overloadIds, - Map overloads, + Map overloads, Object[] args) - throws InterpreterException { - List candidates = new ArrayList<>(); + throws CelException { + int matchingOverloadCount = 0; + ResolvedOverload match = null; + List candidates = null; for (String overloadId : overloadIds) { - Overload overload = overloads.get(overloadId); - if (overload == null) { - throw new InterpreterException.Builder( - "[internal] Unknown overload id '%s' for function '%s'", overloadId, functionName) - .setErrorCode(CelErrorCode.OVERLOAD_NOT_FOUND) - .setLocation(metadata, exprId) - .build(); - } - if (overload.canHandle(args)) { - candidates.add(overloadId); - } - } - if (candidates.size() == 1) { - String overloadId = candidates.get(0); - try { - return overloads.get(overloadId).function.apply(args); - } catch (RuntimeException e) { - throw new InterpreterException.Builder( - e, "Function '%s' failed with arg(s) '%s'", overloadId, Joiner.on(", ").join(args)) - .build(); + ResolvedOverload overload = overloads.get(overloadId); + // If the overload is null, it means that the function was not registered; however, it is + // possible that the overload refers to a late-bound function. + if (overload != null && overload.canHandle(args)) { + if (++matchingOverloadCount > 1) { + if (candidates == null) { + candidates = new ArrayList<>(); + candidates.add(match.getOverloadId()); + } + candidates.add(overloadId); + } + match = overload; } } - if (candidates.size() > 1) { + + if (matchingOverloadCount > 1) { throw new InterpreterException.Builder( "Ambiguous overloads for function '%s'. Matching candidates: %s", - functionName, Joiner.on(",").join(candidates)) + functionName, Joiner.on(", ").join(candidates)) .setErrorCode(CelErrorCode.AMBIGUOUS_OVERLOAD) - .setLocation(metadata, exprId) .build(); } - - throw new InterpreterException.Builder( - "No matching overload for function '%s'. Overload candidates: %s", - functionName, Joiner.on(",").join(overloadIds)) - .setErrorCode(CelErrorCode.OVERLOAD_NOT_FOUND) - .setLocation(metadata, exprId) - .build(); - } - - @Override - public synchronized Object dispatch( - Metadata metadata, long exprId, String functionName, List overloadIds, Object[] args) - throws InterpreterException { - return dispatch(metadata, exprId, functionName, overloadIds, overloads, args); + return Optional.ofNullable(match); } @Override @@ -214,22 +130,16 @@ public synchronized Dispatcher.ImmutableCopy immutableCopy() { @Immutable private static final class ImmutableCopy implements Dispatcher.ImmutableCopy { - private final ImmutableMap overloads; + private final ImmutableMap overloads; - private ImmutableCopy(Map overloads) { + private ImmutableCopy(Map overloads) { this.overloads = ImmutableMap.copyOf(overloads); } @Override - public Object dispatch( - Metadata metadata, - long exprId, - String functionName, - List overloadIds, - Object[] args) - throws InterpreterException { - return DefaultDispatcher.dispatch( - metadata, exprId, functionName, overloadIds, overloads, args); + public Optional findOverload( + String functionName, List overloadIds, Object[] args) throws CelException { + return DefaultDispatcher.findOverload(functionName, overloadIds, overloads, args); } @Override @@ -239,4 +149,31 @@ public Dispatcher.ImmutableCopy immutableCopy() { } private DefaultDispatcher() {} + + @AutoValue + @Immutable + abstract static class ResolvedOverloadImpl 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 FunctionOverload getDefinition(); + + static ResolvedOverload of( + String overloadId, Class[] parameterTypes, FunctionOverload definition) { + return of(overloadId, ImmutableList.copyOf(parameterTypes), definition); + } + + static ResolvedOverload of( + String overloadId, ImmutableList> parameterTypes, FunctionOverload definition) { + return new AutoValue_DefaultDispatcher_ResolvedOverloadImpl( + overloadId, parameterTypes, definition); + } + } } diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java index babec5dda..0db9587b2 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java @@ -14,17 +14,18 @@ package dev.cel.runtime; -import dev.cel.expr.CheckedExpr; -import dev.cel.expr.Value; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.auto.value.AutoValue; +import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import javax.annotation.concurrent.ThreadSafe; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelErrorCode; +import dev.cel.common.CelException; 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; @@ -38,6 +39,7 @@ import dev.cel.common.ast.CelReference; import dev.cel.common.types.CelKind; import dev.cel.common.types.CelType; +import dev.cel.common.types.TypeType; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -53,26 +55,6 @@ /** * Default implementation of the CEL interpreter. * - *

    Use as in: - * - *

    - *   MessageFactory messageFactory = new LinkedMessageFactory();
    - *   RuntimeTypeProvider typeProvider = new DescriptorMessageProvider(messageFactory);
    - *   Dispatcher dispatcher = DefaultDispatcher.create();
    - *   Interpreter interpreter = new DefaultInterpreter(typeProvider, dispatcher);
    - *   Interpretable interpretable = interpreter.createInterpretable(checkedExpr);
    - *   Object result = interpretable.eval(Activation.of("name", value));
    - * 
    - * - *

    Extensions functions can be added in addition to standard functions to the dispatcher as - * needed. - * - *

    Note: {MessageFactory} instances may be combined using the {@link - * MessageFactory.CombinedMessageFactory}. - * - *

    Note: On Android, the {@code DescriptorMessageProvider} is not supported as proto lite does - * not support descriptors. Instead, implement the {@code MessageProvider} interface directly. - * *

    CEL Library Internals. Do Not Use. */ @ThreadSafe @@ -108,10 +90,6 @@ static IntermediateResult create(Object value) { } } - public DefaultInterpreter(RuntimeTypeProvider typeProvider, Dispatcher dispatcher) { - this(typeProvider, dispatcher, CelOptions.LEGACY); - } - /** * Creates a new interpreter * @@ -121,17 +99,11 @@ public DefaultInterpreter(RuntimeTypeProvider typeProvider, Dispatcher dispatche */ public DefaultInterpreter( RuntimeTypeProvider typeProvider, Dispatcher dispatcher, CelOptions celOptions) { - this.typeProvider = Preconditions.checkNotNull(typeProvider); - this.dispatcher = Preconditions.checkNotNull(dispatcher); + this.typeProvider = checkNotNull(typeProvider); + this.dispatcher = checkNotNull(dispatcher); 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); @@ -151,11 +123,11 @@ private static final class DefaultInterpretable Dispatcher dispatcher, CelAbstractSyntaxTree ast, CelOptions celOptions) { - this.typeProvider = Preconditions.checkNotNull(typeProvider); - this.dispatcher = Preconditions.checkNotNull(dispatcher).immutableCopy(); - this.ast = Preconditions.checkNotNull(ast); + this.typeProvider = checkNotNull(typeProvider); + this.dispatcher = checkNotNull(dispatcher).immutableCopy(); + this.ast = checkNotNull(ast); this.metadata = new DefaultMetadata(ast); - this.celOptions = Preconditions.checkNotNull(celOptions); + this.celOptions = checkNotNull(celOptions); } @Override @@ -167,15 +139,32 @@ 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), Optional.empty(), listener); + } + + @Override + public Object eval( + GlobalResolver resolver, + FunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws InterpreterException { + return evalTrackingUnknowns( + RuntimeUnknownResolver.fromResolver(resolver), + Optional.of(lateBoundFunctionResolver), + listener); } @Override public Object evalTrackingUnknowns( - RuntimeUnknownResolver resolver, CelEvaluationListener listener) + RuntimeUnknownResolver resolver, + Optional functionResolver, + CelEvaluationListener listener) throws InterpreterException { + int comprehensionMaxIterations = + celOptions.enableComprehension() ? celOptions.comprehensionMaxIterations() : 0; ExecutionFrame frame = - new ExecutionFrame(listener, resolver, celOptions.comprehensionMaxIterations()); + new ExecutionFrame(listener, resolver, functionResolver, comprehensionMaxIterations); IntermediateResult internalResult = evalInternal(frame, ast.getExpr()); return internalResult.value(); } @@ -223,10 +212,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()) { @@ -267,7 +260,7 @@ private IntermediateResult resolveIdent(ExecutionFrame frame, CelExpr expr, Stri // Check whether the type exists in the type check map as a 'type'. Optional checkedType = ast.getType(expr.id()); if (checkedType.isPresent() && checkedType.get().kind() == CelKind.TYPE) { - Object typeValue = typeProvider.adaptType(checkedType.get()); + TypeType typeValue = CelTypeResolver.adaptType(checkedType.get()); return IntermediateResult.create(typeValue); } @@ -410,14 +403,53 @@ private IntermediateResult evalCall(ExecutionFrame frame, CelExpr expr, CelCall } Object[] argArray = Arrays.stream(argResults).map(IntermediateResult::value).toArray(); + ImmutableList overloadIds = reference.overloadIds(); + ResolvedOverload overload = + findOverloadOrThrow(frame, expr, callExpr.function(), overloadIds, argArray); + try { + Object dispatchResult = overload.getDefinition().apply(argArray); + if (celOptions.unwrapWellKnownTypesOnFunctionDispatch()) { + dispatchResult = typeProvider.adapt(dispatchResult); + } + return IntermediateResult.create(attr, dispatchResult); + } catch (CelException ce) { + throw InterpreterException.wrapOrThrow(metadata, expr.id(), ce); + } catch (RuntimeException e) { + throw new InterpreterException.Builder( + e, + "Function '%s' failed with arg(s) '%s'", + overload.getOverloadId(), + Joiner.on(", ").join(argArray)) + .build(); + } + } - Object dispatchResult = - dispatcher.dispatch( - metadata, expr.id(), callExpr.function(), reference.overloadIds(), argArray); - if (celOptions.unwrapWellKnownTypesOnFunctionDispatch()) { - dispatchResult = typeProvider.adapt(dispatchResult); + private ResolvedOverload findOverloadOrThrow( + ExecutionFrame frame, + CelExpr expr, + String functionName, + List overloadIds, + Object[] args) + throws InterpreterException { + try { + Optional funcImpl = + dispatcher.findOverload(functionName, overloadIds, args); + if (funcImpl.isPresent()) { + return funcImpl.get(); + } + return frame + .findOverload(functionName, overloadIds, args) + .orElseThrow( + () -> + new InterpreterException.Builder( + "No matching overload for function '%s'. Overload candidates: %s", + functionName, Joiner.on(",").join(overloadIds)) + .setErrorCode(CelErrorCode.OVERLOAD_NOT_FOUND) + .setLocation(metadata, expr.id()) + .build()); + } catch (CelException e) { + throw InterpreterException.wrapOrThrow(metadata, expr.id(), e); } - return IntermediateResult.create(attr, dispatchResult); } private Optional maybeContainerIndexAttribute( @@ -591,6 +623,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()) @@ -604,9 +640,9 @@ private IntermediateResult evalType(ExecutionFrame frame, CelCall callExpr) .setLocation(metadata, typeExprArg.id()) .build()); - Value checkedTypeValue = typeProvider.adaptType(checkedType); - Object typeValue = typeProvider.resolveObjectType(argResult.value(), checkedTypeValue); - return IntermediateResult.create(typeValue); + CelType checkedTypeValue = CelTypeResolver.adaptType(checkedType); + return IntermediateResult.create( + CelTypeResolver.resolveObjectType(argResult.value(), checkedTypeValue)); } private IntermediateResult evalOptionalOr(ExecutionFrame frame, CelCall callExpr) @@ -680,9 +716,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()) @@ -937,16 +971,19 @@ private static class ExecutionFrame { private final CelEvaluationListener evaluationListener; private final int maxIterations; private final ArrayDeque resolvers; + private final Optional lateBoundFunctionResolver; private RuntimeUnknownResolver currentResolver; private int iterations; private ExecutionFrame( CelEvaluationListener evaluationListener, RuntimeUnknownResolver resolver, + Optional lateBoundFunctionResolver, int maxIterations) { this.evaluationListener = evaluationListener; this.resolvers = new ArrayDeque<>(); this.resolvers.add(resolver); + this.lateBoundFunctionResolver = lateBoundFunctionResolver; this.currentResolver = resolver; this.maxIterations = maxIterations; } @@ -959,6 +996,14 @@ private RuntimeUnknownResolver getResolver() { return currentResolver; } + private Optional findOverload( + String function, List overloadIds, Object[] args) throws CelException { + if (lateBoundFunctionResolver.isPresent()) { + return lateBoundFunctionResolver.get().findOverload(function, overloadIds, args); + } + return Optional.empty(); + } + private void incrementIterations() throws InterpreterException { if (maxIterations < 0) { return; diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultMetadata.java b/runtime/src/main/java/dev/cel/runtime/DefaultMetadata.java index 65f719817..43cce4e9c 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultMetadata.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultMetadata.java @@ -14,16 +14,14 @@ package dev.cel.runtime; -import dev.cel.expr.CheckedExpr; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.annotations.Internal; /** - * Metadata implementation based on {@link CheckedExpr}. + * Metadata implementation based on {@link CelAbstractSyntaxTree}. * *

    CEL Library Internals. Do Not Use. */ @@ -37,11 +35,6 @@ public DefaultMetadata(CelAbstractSyntaxTree ast) { this.ast = Preconditions.checkNotNull(ast); } - @Deprecated - public DefaultMetadata(CheckedExpr checkedExpr) { - this(CelProtoAbstractSyntaxTree.fromCheckedExpr(checkedExpr).getAst()); - } - @Override public String getLocation() { return ast.getSource().getDescription(); diff --git a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java index f4fbbfe27..660fd75ca 100644 --- a/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java +++ b/runtime/src/main/java/dev/cel/runtime/DescriptorMessageProvider.java @@ -14,8 +14,6 @@ package dev.cel.runtime; -import dev.cel.expr.Type; -import dev.cel.expr.Value; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; import com.google.protobuf.Descriptors.Descriptor; @@ -31,7 +29,6 @@ import dev.cel.common.internal.DynamicProto; import dev.cel.common.internal.ProtoAdapter; import dev.cel.common.internal.ProtoMessageFactory; -import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypes; import java.util.Map; import java.util.Optional; @@ -50,7 +47,6 @@ @Internal public final class DescriptorMessageProvider implements RuntimeTypeProvider { private final ProtoMessageFactory protoMessageFactory; - private final TypeResolver typeResolver; @SuppressWarnings("Immutable") private final ProtoAdapter protoAdapter; @@ -82,33 +78,12 @@ public DescriptorMessageProvider( * when adapting from proto to CEL and vice versa. */ public DescriptorMessageProvider(ProtoMessageFactory protoMessageFactory, CelOptions celOptions) { - this.typeResolver = StandardTypeResolver.getInstance(celOptions); this.protoMessageFactory = protoMessageFactory; this.protoAdapter = new ProtoAdapter( DynamicProto.create(protoMessageFactory), celOptions.enableUnsignedLongs()); } - @Override - @Nullable - public Value resolveObjectType(Object obj, @Nullable Value checkedTypeValue) { - return typeResolver.resolveObjectType(obj, checkedTypeValue); - } - - /** {@inheritDoc} */ - @Override - public Value adaptType(CelType type) { - return typeResolver.adaptType(type); - } - - @Nullable - @Override - @Deprecated - /** {@inheritDoc} */ - public Value adaptType(@Nullable Type type) { - return typeResolver.adaptType(type); - } - @Nullable @Override public Object createMessage(String messageName, Map values) { diff --git a/runtime/src/main/java/dev/cel/runtime/Dispatcher.java b/runtime/src/main/java/dev/cel/runtime/Dispatcher.java index fcaa087aa..6482290f3 100644 --- a/runtime/src/main/java/dev/cel/runtime/Dispatcher.java +++ b/runtime/src/main/java/dev/cel/runtime/Dispatcher.java @@ -17,7 +17,6 @@ import com.google.errorprone.annotations.Immutable; import javax.annotation.concurrent.ThreadSafe; import dev.cel.common.annotations.Internal; -import java.util.List; /** * An object which implements dispatching of function calls. @@ -26,24 +25,7 @@ */ @ThreadSafe @Internal -public interface Dispatcher { - - /** - * Invokes a function based on given parameters. - * - * @param metadata Metadata used for error reporting. - * @param exprId Expression identifier which can be used together with {@code metadata} to get - * information about the dispatch target for error reporting. - * @param functionName the logical name of the function being invoked. - * @param overloadIds A list of function overload ids. The dispatcher selects the unique overload - * from this list with matching arguments. - * @param args The arguments to pass to the function. - * @return The result of the function call. - * @throws InterpreterException if something goes wrong. - */ - Object dispatch( - Metadata metadata, long exprId, String functionName, List overloadIds, Object[] args) - throws InterpreterException; +public interface Dispatcher extends FunctionResolver { /** * Returns an {@link ImmutableCopy} from current instance. diff --git a/runtime/src/main/java/dev/cel/runtime/FunctionOverload.java b/runtime/src/main/java/dev/cel/runtime/FunctionOverload.java new file mode 100644 index 000000000..132a128db --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/FunctionOverload.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.runtime; + +import com.google.errorprone.annotations.Immutable; +import dev.cel.common.CelException; + +/** Interface describing the general signature of all CEL custom function implementations. */ +@FunctionalInterface +@Immutable +public interface FunctionOverload { + + /** Evaluate a set of arguments throwing a {@code CelException} on error. */ + Object apply(Object[] args) throws CelException; + + /** + * 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 CelException; + } + + /** + * 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 CelException; + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/FunctionResolver.java b/runtime/src/main/java/dev/cel/runtime/FunctionResolver.java new file mode 100644 index 000000000..4d7614df0 --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/FunctionResolver.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.runtime; + +import javax.annotation.concurrent.ThreadSafe; +import dev.cel.common.CelException; +import dev.cel.common.annotations.Internal; +import java.util.List; +import java.util.Optional; + +/** + * Interface to a resolver for CEL functions based on the function name, overload ids, and + * arguments. + * + *

    CEL Library Internals. Do Not Use. + */ +@ThreadSafe +@Internal +public interface FunctionResolver { + + /** + * Finds a specific function overload to invoke based on given parameters. + * + * @param functionName the logical name of the function being invoked. + * @param overloadIds A list of function overload ids. The dispatcher selects the unique overload + * from this list with matching arguments. + * @param args The arguments to pass to the function. + * @return an optional value of the resolved overload. + * @throws CelException if the overload resolution is ambiguous, + */ + Optional findOverload( + String functionName, List overloadIds, Object[] args) throws CelException; +} diff --git a/runtime/src/main/java/dev/cel/runtime/Interpretable.java b/runtime/src/main/java/dev/cel/runtime/Interpretable.java index 0c967416a..c967af92a 100644 --- a/runtime/src/main/java/dev/cel/runtime/Interpretable.java +++ b/runtime/src/main/java/dev/cel/runtime/Interpretable.java @@ -29,5 +29,24 @@ public interface Interpretable { /** Runs interpretation with the given activation which supplies name/value bindings. */ Object eval(GlobalResolver resolver) throws InterpreterException; + /** + * Runs interpretation with the given activation which supplies name/value bindings. + * + *

    This method allows for evaluation listeners to be provided per-evaluation. + */ Object eval(GlobalResolver resolver, CelEvaluationListener listener) throws InterpreterException; + + /** + * Runs interpretation with the given activation which supplies name/value bindings. + * + *

    This method allows for late-binding functions to be provided per-evaluation, which can be + * useful for binding functions which might have side-effects that are not observable to CEL + * directly such as recording telemetry or evaluation state in a more granular fashion than a more + * general evaluation listener might permit. + */ + Object eval( + GlobalResolver resolver, + FunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws InterpreterException; } 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. * diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java index e3e09aa24..2cb1685f1 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterException.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterException.java @@ -17,6 +17,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import dev.cel.common.CelErrorCode; +import dev.cel.common.CelException; import dev.cel.common.CelRuntimeException; import dev.cel.common.annotations.Internal; import dev.cel.common.internal.SafeStringFormatter; @@ -31,12 +32,7 @@ *

    CEL Library Internals. Do Not Use. */ @Internal -public class InterpreterException extends Exception { - private final CelErrorCode errorCode; - - public CelErrorCode getErrorCode() { - return errorCode; - } +public class InterpreterException extends CelException { /** Builder for InterpreterException. */ public static class Builder { @@ -100,8 +96,24 @@ public InterpreterException build() { } } + public static InterpreterException wrapOrThrow(Metadata metadata, long exprId, Exception e) { + if (e instanceof InterpreterException) { + return (InterpreterException) e; + } + if (e instanceof CelException) { + return new InterpreterException.Builder(e.getMessage()) + .setCause(e.getCause()) + .setErrorCode(((CelException) e).getErrorCode()) + .build(); + } + return new InterpreterException.Builder(e.getMessage()).setCause(e).build(); + } + + public static InterpreterException wrapOrThrow(Exception e) { + return wrapOrThrow(null, 0, e); + } + private InterpreterException(String message, Throwable cause, CelErrorCode errorCode) { - super(message, cause); - this.errorCode = errorCode; + super(message, cause, errorCode); } } diff --git a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java index 7f2808c0e..cce47d62e 100644 --- a/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java +++ b/runtime/src/main/java/dev/cel/runtime/InterpreterUtil.java @@ -14,12 +14,8 @@ package dev.cel.runtime; -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,44 +52,18 @@ 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; + return obj instanceof CelUnknownSet; } - /** - * Combine multiple ExprValue objects which has UnknownSet into one ExprValue - * - * @param objs ExprValue objects which has UnknownSet - * @return A new ExprValue object which has all unknown expr ids from input objects, without - * duplication. - */ - public static ExprValue combineUnknownExprValue(Object... objs) { - UnknownSet.Builder unknownsetBuilder = UnknownSet.newBuilder(); + static CelUnknownSet combineUnknownExprValue(Object... objs) { Set ids = new LinkedHashSet<>(); for (Object object : objs) { if (isUnknown(object)) { - ids.addAll(((ExprValue) object).getUnknown().getExprsList()); + ids.addAll(((CelUnknownSet) object).unknownExprIds()); } } - unknownsetBuilder.addAllExprs(ids); - 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)); - } - /** - * Create an ExprValue object has UnknownSet, from a list of unknown expr ids - * - * @param ids List of unknown expr ids - * @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(); + return CelUnknownSet.create(ids); } /** @@ -135,15 +105,11 @@ public static Object shortcircuitUnknownOrThrowable(Object left, Object right) public static Object valueOrUnknown(@Nullable Object valueOrThrowable, Long id) { // Handle the unknown value case. if (isUnknown(valueOrThrowable)) { - ExprValue value = (ExprValue) valueOrThrowable; - if (value.getUnknown().getExprsCount() != 0) { - return valueOrThrowable; - } - return createUnknownExprValue(id); + return CelUnknownSet.create(id); } // Handle the null value case. if (valueOrThrowable == null) { - return createUnknownExprValue(id); + return CelUnknownSet.create(id); } return valueOrThrowable; } diff --git a/runtime/src/main/java/dev/cel/runtime/Registrar.java b/runtime/src/main/java/dev/cel/runtime/Registrar.java index 92eb8b31c..3a3afa1d0 100644 --- a/runtime/src/main/java/dev/cel/runtime/Registrar.java +++ b/runtime/src/main/java/dev/cel/runtime/Registrar.java @@ -14,7 +14,6 @@ package dev.cel.runtime; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import dev.cel.common.annotations.Internal; import java.util.List; @@ -27,33 +26,23 @@ @Internal public interface Registrar { - /** Interface to a general function. */ + /** Interface describing the general signature of all CEL custom function implementations. */ @Immutable - @FunctionalInterface - interface Function { - @CanIgnoreReturnValue - Object apply(Object[] args) throws InterpreterException; - } + interface Function extends FunctionOverload {} /** - * Interface to a typed unary function without activation argument. Convenience for the {@code - * add} methods. + * Helper interface for describing unary functions where the type-parameter is used to improve + * compile-time correctness of function bindings. */ @Immutable - @FunctionalInterface - interface UnaryFunction { - Object apply(T arg) throws InterpreterException; - } + interface UnaryFunction extends FunctionOverload.Unary {} /** - * Interface to a typed binary function without activation argument. Convenience for the {@code - * add} methods. + * Helper interface for describing binary functions where the type parameters are used to improve + * compile-time correctness of function bindings. */ @Immutable - @FunctionalInterface - interface BinaryFunction { - Object apply(T1 arg1, T2 arg2) throws InterpreterException; - } + interface BinaryFunction extends FunctionOverload.Binary {} /** Adds a unary function to the dispatcher. */ void add(String overloadId, Class argType, UnaryFunction function); diff --git a/runtime/src/main/java/dev/cel/runtime/ResolvedOverload.java b/runtime/src/main/java/dev/cel/runtime/ResolvedOverload.java new file mode 100644 index 000000000..4bd0e9a6e --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/ResolvedOverload.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 dev.cel.runtime; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.MessageLite; +import java.util.Map; + +/** + * Representation of a function overload which has been resolved to a specific set of argument types + * and a function definition. + */ +@Immutable +public interface ResolvedOverload { + + /** The overload id of the function. */ + String getOverloadId(); + + /** The types of the function parameters. */ + ImmutableList> getParameterTypes(); + + /** The function definition. */ + FunctionOverload getDefinition(); + + /** + * Returns true if the overload's expected argument types match the types of the given arguments. + */ + default boolean canHandle(Object[] arguments) { + ImmutableList> parameterTypes = getParameterTypes(); + if (parameterTypes.size() != arguments.length) { + return false; + } + for (int i = 0; i < parameterTypes.size(); i++) { + Class paramType = parameterTypes.get(i); + Object arg = arguments[i]; + if (arg == null) { + // null can be assigned to messages, maps, and to objects. + if (paramType != Object.class + && !MessageLite.class.isAssignableFrom(paramType) + && !Map.class.isAssignableFrom(paramType)) { + return false; + } + continue; + } + if (!paramType.isAssignableFrom(arg.getClass())) { + return false; + } + } + return true; + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProvider.java b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProvider.java index 7df4e26ad..97e4f3af1 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProvider.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProvider.java @@ -25,4 +25,4 @@ */ @Immutable @Internal -public interface RuntimeTypeProvider extends MessageProvider, TypeResolver {} +public interface RuntimeTypeProvider extends MessageProvider {} diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java index dcb2b4ec3..36bd054f3 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeTypeProviderLegacyImpl.java @@ -14,10 +14,7 @@ package dev.cel.runtime; -import dev.cel.expr.Type; -import dev.cel.expr.Value; 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; @@ -25,8 +22,6 @@ import dev.cel.common.annotations.Internal; import dev.cel.common.internal.CelDescriptorPool; import dev.cel.common.internal.DynamicProto; -import dev.cel.common.types.CelType; -import dev.cel.common.types.TypeType; import dev.cel.common.values.CelValue; import dev.cel.common.values.CelValueProvider; import dev.cel.common.values.ProtoCelValueConverter; @@ -34,7 +29,6 @@ import dev.cel.common.values.StringValue; import java.util.Map; import java.util.NoSuchElementException; -import org.jspecify.annotations.Nullable; /** Bridge between the old RuntimeTypeProvider and CelValueProvider APIs. */ @Internal @@ -43,7 +37,6 @@ public final class RuntimeTypeProviderLegacyImpl implements RuntimeTypeProvider private final CelValueProvider valueProvider; private final ProtoCelValueConverter protoCelValueConverter; - private final TypeResolver standardTypeResolver; @VisibleForTesting public RuntimeTypeProviderLegacyImpl( @@ -54,7 +47,6 @@ public RuntimeTypeProviderLegacyImpl( this.valueProvider = valueProvider; this.protoCelValueConverter = ProtoCelValueConverter.newInstance(celOptions, celDescriptorPool, dynamicProto); - this.standardTypeResolver = StandardTypeResolver.getInstance(celOptions); } @Override @@ -115,28 +107,6 @@ public Object adapt(Object message) { return unwrapCelValue(protoCelValueConverter.fromJavaObjectToCelValue(message)); } - @Override - public Value resolveObjectType(Object obj, Value checkedTypeValue) { - // Presently, Java only supports evaluation of checked-only expressions. - Preconditions.checkNotNull(checkedTypeValue); - return standardTypeResolver.resolveObjectType(obj, checkedTypeValue); - } - - @Override - public Value adaptType(CelType type) { - Preconditions.checkNotNull(type); - if (type instanceof TypeType) { - return createTypeValue(((TypeType) type).containingTypeName()); - } - - return createTypeValue(type.name()); - } - - @Override - public @Nullable Value adaptType(@Nullable Type type) { - throw new UnsupportedOperationException("This should only be called with native CelType."); - } - /** * DefaultInterpreter cannot handle CelValue and instead expects plain Java objects. * @@ -145,8 +115,4 @@ public Value adaptType(CelType type) { private Object unwrapCelValue(CelValue object) { return protoCelValueConverter.fromCelValueToJavaObject(object); } - - private static Value createTypeValue(String name) { - return Value.newBuilder().setTypeValue(name).build(); - } } diff --git a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java index 1c1be9b94..f7b8728cf 100644 --- a/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java +++ b/runtime/src/main/java/dev/cel/runtime/RuntimeUnknownResolver.java @@ -53,7 +53,7 @@ public static RuntimeUnknownResolver fromResolver(GlobalResolver resolver) { // 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); } public static Builder builder() { diff --git a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java index c69c98271..be6a6cc94 100644 --- a/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java +++ b/runtime/src/main/java/dev/cel/runtime/StandardFunctions.java @@ -24,7 +24,6 @@ import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; -import com.google.re2j.PatternSyntaxException; import dev.cel.common.CelErrorCode; import dev.cel.common.CelOptions; import dev.cel.common.annotations.Internal; @@ -42,69 +41,25 @@ import java.util.Map; import java.util.Optional; -/** Adds standard functions to a {@link Registrar}. */ +/** + * Adds standard functions to a {@link Registrar}. + * + * @deprecated Do not use. This only exists to maintain compatibility with the legacy async + * interpreter, which will be removed in the future. + */ @Internal +@Deprecated public class StandardFunctions { private static final String UTC = "UTC"; - /** - * Adds CEL standard functions to the given registrar. - * - *

    Note this does not add functions which do not use strict argument evaluation order, as - * 'conditional', 'logical_and', and 'logical_or'. Those functions need to be dealt with ad-hoc. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - public static void add(Registrar registrar, DynamicProto dynamicProto, CelOptions celOptions) { - RuntimeEquality runtimeEquality = new RuntimeEquality(dynamicProto); - addNonInlined(registrar, runtimeEquality, celOptions); - - // String functions - registrar.add( - "matches", - String.class, - String.class, - (String string, String regexp) -> { - try { - return RuntimeHelpers.matches(string, regexp, celOptions); - } catch (PatternSyntaxException e) { - throw new InterpreterException.Builder(e.getMessage()) - .setCause(e) - .setErrorCode(CelErrorCode.INVALID_ARGUMENT) - .build(); - } - }); - // Duplicate receiver-style matches overload. - registrar.add( - "matches_string", - String.class, - String.class, - (String string, String regexp) -> { - try { - return RuntimeHelpers.matches(string, regexp, celOptions); - } catch (PatternSyntaxException e) { - throw new InterpreterException.Builder(e.getMessage()) - .setCause(e) - .setErrorCode(CelErrorCode.INVALID_ARGUMENT) - .build(); - } - }); - // In operator: b in a - registrar.add( - "in_list", - Object.class, - List.class, - (Object value, List list) -> runtimeEquality.inList(list, value, celOptions)); - registrar.add( - "in_map", - Object.class, - Map.class, - (Object key, Map map) -> runtimeEquality.inMap(map, key, celOptions)); - } - /** * Adds CEL standard functions to the given registrar, omitting those that can be inlined by * {@code FuturesInterpreter}. + * + * @deprecated Do not use. This only exists to maintain compatibility with the legacy async + * interpreter, will be removed in the future. */ + @Deprecated public static void addNonInlined(Registrar registrar, CelOptions celOptions) { addNonInlined( registrar, @@ -116,7 +71,7 @@ public static void addNonInlined(Registrar registrar, CelOptions celOptions) { * Adds CEL standard functions to the given registrar, omitting those that can be inlined by * {@code FuturesInterpreter}. */ - public static void addNonInlined( + private static void addNonInlined( Registrar registrar, RuntimeEquality runtimeEquality, CelOptions celOptions) { addBoolFunctions(registrar); addBytesFunctions(registrar); diff --git a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java b/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java deleted file mode 100644 index c560827cc..000000000 --- a/runtime/src/main/java/dev/cel/runtime/StandardTypeResolver.java +++ /dev/null @@ -1,239 +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 static com.google.common.base.Preconditions.checkNotNull; - -import dev.cel.expr.Type; -import dev.cel.expr.Type.PrimitiveType; -import dev.cel.expr.Type.TypeKindCase; -import dev.cel.expr.Value; -import dev.cel.expr.Value.KindCase; -import com.google.common.collect.ImmutableMap; -import com.google.common.primitives.UnsignedLong; -import com.google.errorprone.annotations.Immutable; -import com.google.protobuf.ByteString; -import com.google.protobuf.MessageOrBuilder; -import com.google.protobuf.NullValue; -import dev.cel.common.CelOptions; -import dev.cel.common.annotations.Internal; -import dev.cel.common.types.CelKind; -import dev.cel.common.types.CelType; -import dev.cel.common.types.TypeType; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import org.jspecify.annotations.Nullable; - -/** - * The {@code StandardTypeResolver} implements the {@link TypeResolver} and resolves types supported - * by the CEL standard environment. - * - *

    CEL Library Internals. Do Not Use. - */ -@Immutable -@Internal -public final class StandardTypeResolver implements TypeResolver { - - /** - * Obtain a singleton instance of the {@link StandardTypeResolver} appropriate for the {@code - * celOptions} provided. - */ - public static TypeResolver getInstance(CelOptions celOptions) { - return celOptions.enableUnsignedLongs() ? INSTANCE_WITH_UNSIGNED_LONGS : INSTANCE; - } - - private static final TypeResolver INSTANCE = - new StandardTypeResolver(commonTypes(/* unsignedLongs= */ false)); - - private static final TypeResolver INSTANCE_WITH_UNSIGNED_LONGS = - new StandardTypeResolver(commonTypes(/* unsignedLongs= */ true)); - - // Type of type which is modelled as a value instance rather than as a Java POJO. - private static final Value TYPE_VALUE = createType("type"); - - // Built-in types. - private static ImmutableMap> commonTypes(boolean unsignedLongs) { - return ImmutableMap.>builder() - .put(createType("bool"), Boolean.class) - .put(createType("bytes"), ByteString.class) - .put(createType("double"), Double.class) - .put(createType("int"), Long.class) - .put(createType("uint"), unsignedLongs ? UnsignedLong.class : Long.class) - .put(createType("string"), String.class) - .put(createType("null_type"), NullValue.class) - // Aggregate types. - .put(createType("list"), Collection.class) - .put(createType("map"), Map.class) - // Optional type - .put(createType("optional_type"), Optional.class) - .buildOrThrow(); - } - - private final ImmutableMap> types; - - private StandardTypeResolver(ImmutableMap> types) { - this.types = types; - } - - @Nullable - @Override - public Value resolveObjectType(Object obj, @Nullable Value checkedTypeValue) { - if (checkedTypeValue != null && (obj instanceof Long || obj instanceof NullValue)) { - return checkedTypeValue; - } - return resolveObjectType(obj); - } - - @Nullable - private Value resolveObjectType(Object obj) { - for (Value type : types.keySet()) { - Class impl = types.get(type); - // Generally, the type will be an instance of a class. - if (impl.isInstance(obj)) { - return type; - } - } - // In the case 'type' values, the obj will be a api.expr.Value. - if (obj instanceof Value) { - Value objVal = (Value) obj; - if (objVal.getKindCase() == KindCase.TYPE_VALUE) { - return TYPE_VALUE; - } - } - // Otherwise, this is a protobuf type. - if (obj instanceof MessageOrBuilder) { - MessageOrBuilder msg = (MessageOrBuilder) obj; - return createType(msg.getDescriptorForType().getFullName()); - } - return null; - } - - /** {@inheritDoc} */ - @Override - public @Nullable Value adaptType(CelType type) { - checkNotNull(type); - // TODO: Add enum type support here. - Value.Builder typeValue = Value.newBuilder(); - switch (type.kind()) { - case OPAQUE: - case STRUCT: - return typeValue.setTypeValue(type.name()).build(); - case LIST: - return typeValue.setTypeValue("list").build(); - case MAP: - return typeValue.setTypeValue("map").build(); - case TYPE: - CelType typeOfType = ((TypeType) type).type(); - if (typeOfType.kind() == CelKind.DYN) { - return typeValue.setTypeValue("type").build(); - } - return adaptType(typeOfType); - case NULL_TYPE: - return typeValue.setTypeValue("null_type").build(); - case DURATION: - return typeValue.setTypeValue("google.protobuf.Duration").build(); - case TIMESTAMP: - return typeValue.setTypeValue("google.protobuf.Timestamp").build(); - case BOOL: - return typeValue.setTypeValue("bool").build(); - case BYTES: - return typeValue.setTypeValue("bytes").build(); - case DOUBLE: - return typeValue.setTypeValue("double").build(); - case INT: - return typeValue.setTypeValue("int").build(); - case STRING: - return typeValue.setTypeValue("string").build(); - case UINT: - return typeValue.setTypeValue("uint").build(); - default: - break; - } - return null; - } - - /** {@inheritDoc} */ - @Override - @Deprecated - public @Nullable Value adaptType(@Nullable Type type) { - if (type == null) { - return null; - } - // TODO: Add enum type support here. - Value.Builder typeValue = Value.newBuilder(); - switch (type.getTypeKindCase()) { - case ABSTRACT_TYPE: - return typeValue.setTypeValue(type.getAbstractType().getName()).build(); - case MESSAGE_TYPE: - return typeValue.setTypeValue(type.getMessageType()).build(); - case LIST_TYPE: - return typeValue.setTypeValue("list").build(); - case MAP_TYPE: - return typeValue.setTypeValue("map").build(); - case TYPE: - Type typeOfType = type.getType(); - if (typeOfType.getTypeKindCase() == TypeKindCase.DYN) { - return typeValue.setTypeValue("type").build(); - } - return adaptType(typeOfType); - case NULL: - return typeValue.setTypeValue("null_type").build(); - case PRIMITIVE: - return adaptPrimitive(type.getPrimitive()); - case WRAPPER: - return adaptPrimitive(type.getWrapper()); - case WELL_KNOWN: - switch (type.getWellKnown()) { - case DURATION: - return typeValue.setTypeValue("google.protobuf.Duration").build(); - case TIMESTAMP: - return typeValue.setTypeValue("google.protobuf.Timestamp").build(); - default: - break; - } - break; - default: - break; - } - return null; - } - - @Nullable - private static Value adaptPrimitive(PrimitiveType primitiveType) { - Value.Builder typeValue = Value.newBuilder(); - switch (primitiveType) { - case BOOL: - return typeValue.setTypeValue("bool").build(); - case BYTES: - return typeValue.setTypeValue("bytes").build(); - case DOUBLE: - return typeValue.setTypeValue("double").build(); - case INT64: - return typeValue.setTypeValue("int").build(); - case STRING: - return typeValue.setTypeValue("string").build(); - case UINT64: - return typeValue.setTypeValue("uint").build(); - default: - break; - } - return null; - } - - private static Value createType(String name) { - return Value.newBuilder().setTypeValue(name).build(); - } -} diff --git a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java b/runtime/src/main/java/dev/cel/runtime/TypeResolver.java deleted file mode 100644 index 4bfa9ae7d..000000000 --- a/runtime/src/main/java/dev/cel/runtime/TypeResolver.java +++ /dev/null @@ -1,67 +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.runtime; - -import dev.cel.expr.Type; -import dev.cel.expr.Value; -import com.google.errorprone.annotations.Immutable; -import dev.cel.common.annotations.Internal; -import dev.cel.common.types.CelType; -import org.jspecify.annotations.Nullable; - -/** - * The {@code TypeResolver} determines the CEL type of Java-native values and assists with adapting - * check-time types to runtime values. - * - *

    CEL Library Internals. Do Not Use. - */ -@Immutable -@Internal -public interface TypeResolver { - - /** - * Resolve the CEL type of the {@code obj}, using the {@code checkedTypeValue} as hint for type - * disambiguation. - * - *

    The {@code checkedTypeValue} indicates the statically determined type of the object at - * check-time. Often, the check-time and runtime phases agree, but there are cases where the - * runtime type is ambiguous, as is the case when a {@code Long} value is supplied as this could - * either be an int, uint, or enum type. - * - *

    Type resolution is biased toward the runtime value type, given the dynamically typed nature - * of CEL. - */ - @Nullable Value resolveObjectType(Object obj, @Nullable Value checkedTypeValue); - - /** - * Adapt the check-time {@code type} instance to a runtime {@code Value}. - * - *

    When the checked {@code type} does not have a runtime equivalent, e.g. {@code Type#DYN}, the - * return value will be {@code null}. - */ - @Nullable Value adaptType(CelType type); - - /** - * Adapt the check-time {@code type} instance to a runtime {@code Value}. - * - *

    When the checked {@code type} does not have a runtime equivalent, e.g. {@code Type#DYN}, the - * return value will be {@code null}. - * - * @deprecated use {@link #adaptType(CelType)} instead. This only exists to maintain compatibility - * with legacy async evaluator. - */ - @Deprecated - @Nullable Value adaptType(@Nullable Type type); -} diff --git a/runtime/src/main/java/dev/cel/runtime/UnknownTrackingInterpretable.java b/runtime/src/main/java/dev/cel/runtime/UnknownTrackingInterpretable.java index 96dbd2b6d..a76c198c1 100644 --- a/runtime/src/main/java/dev/cel/runtime/UnknownTrackingInterpretable.java +++ b/runtime/src/main/java/dev/cel/runtime/UnknownTrackingInterpretable.java @@ -15,6 +15,7 @@ package dev.cel.runtime; import dev.cel.common.annotations.Internal; +import java.util.Optional; /** * An interpretable that allows for tracking unknowns at runtime. @@ -23,6 +24,18 @@ */ @Internal public interface UnknownTrackingInterpretable { - Object evalTrackingUnknowns(RuntimeUnknownResolver resolver, CelEvaluationListener listener) + /** + * Runs interpretation with the given activation which supplies name/value bindings with the + * ability to track and resolve unknown variables as they are encountered. + * + *

    This method allows for late-binding functions to be provided per-evaluation, which can be + * useful for binding functions which might have side-effects that are not observable to CEL + * directly such as recording telemetry or evaluation state in a more granular fashion than a more + * general evaluation listener might permit. + */ + Object evalTrackingUnknowns( + RuntimeUnknownResolver resolver, + Optional lateBoundFunctionResolver, + CelEvaluationListener listener) throws InterpreterException; } diff --git a/runtime/src/test/java/dev/cel/runtime/ActivationTest.java b/runtime/src/test/java/dev/cel/runtime/ActivationTest.java index 003a72e05..fc7d4a9ac 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.expr.conformance.proto3.NestedTestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.expr.conformance.proto3.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 6210df4ec..8aaa60ed1 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -31,18 +31,23 @@ java_library( "//common/internal:well_known_proto", "//common/types", "//common/types:cel_v1alpha1_types", + "//common/types:message_type_provider", "//compiler", "//compiler:compiler_builder", + "//extensions:optional_library", "//parser:macro", "//parser:unparser", + "//policy:config", + "//policy:config_parser", + "//policy:parser_factory", "//runtime", "//runtime:evaluation_listener", "//runtime:interpreter", "//runtime:runtime_helper", "//runtime:unknown_attributes", "//runtime:unknown_options", - "@cel_spec//proto/test/v1/proto2:test_all_types_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_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", "@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/CelAttributeParserTest.java b/runtime/src/test/java/dev/cel/runtime/CelAttributeParserTest.java index 58e5f2735..e2d463555 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelAttributeParserTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelAttributeParserTest.java @@ -101,19 +101,19 @@ public void parse_unsupportedExprKindThrows() { Assert.assertThrows( IllegalArgumentException.class, () -> CelAttributeParser.parse("1 / 2")); - assertThat(iae).hasMessageThat().contains("_/_(CONST_EXPR, CONST_EXPR)"); + assertThat(iae).hasMessageThat().contains("_/_(CONSTANT, CONSTANT)"); iae = Assert.assertThrows( IllegalArgumentException.class, () -> CelAttributeParser.parse("123.field")); - assertThat(iae).hasMessageThat().contains("CONST_EXPR"); + assertThat(iae).hasMessageThat().contains("CelConstant"); iae = Assert.assertThrows( IllegalArgumentException.class, () -> CelAttributeParser.parse("a && b")); - assertThat(iae).hasMessageThat().contains("_&&_(IDENT_EXPR, IDENT_EXPR)"); + assertThat(iae).hasMessageThat().contains("_&&_(IDENT, IDENT)"); } @Test diff --git a/runtime/src/test/java/dev/cel/runtime/CelLateFunctionBindingsTest.java b/runtime/src/test/java/dev/cel/runtime/CelLateFunctionBindingsTest.java new file mode 100644 index 000000000..c69a5320a --- /dev/null +++ b/runtime/src/test/java/dev/cel/runtime/CelLateFunctionBindingsTest.java @@ -0,0 +1,146 @@ +// 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.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.common.primitives.UnsignedLong; +import dev.cel.common.CelErrorCode; +import dev.cel.common.CelException; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; +import java.util.Optional; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link CelLateFunctionBindings}. */ +@RunWith(JUnit4.class) +public final class CelLateFunctionBindingsTest { + + @Test + public void findOverload_singleMatchingFunction_isPresent() + throws CelException, InterpreterException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("increment_int", Long.class, (arg) -> arg + 1), + CelFunctionBinding.from( + "increment_uint", UnsignedLong.class, (arg) -> arg.plus(UnsignedLong.ONE))); + Optional overload = + bindings.findOverload( + "increment", ImmutableList.of("increment_int", "increment_uint"), new Object[] {1L}); + assertThat(overload).isPresent(); + assertThat(overload.get().getOverloadId()).isEqualTo("increment_int"); + assertThat(overload.get().getParameterTypes()).containsExactly(Long.class); + assertThat(overload.get().getDefinition().apply(new Object[] {1L})).isEqualTo(2L); + } + + @Test + public void findOverload_noMatchingFunctionSameArgCount_isEmpty() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("increment_int", Long.class, (arg) -> arg + 1), + CelFunctionBinding.from( + "increment_uint", UnsignedLong.class, (arg) -> arg.plus(UnsignedLong.ONE))); + Optional overload = + bindings.findOverload( + "increment", ImmutableList.of("increment_int", "increment_uint"), new Object[] {1.0}); + assertThat(overload).isEmpty(); + } + + @Test + public void findOverload_noMatchingFunctionDifferentArgCount_isEmpty() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("increment_int", Long.class, (arg) -> arg + 1), + CelFunctionBinding.from( + "increment_uint", UnsignedLong.class, (arg) -> arg.plus(UnsignedLong.ONE))); + Optional overload = + bindings.findOverload( + "increment", + ImmutableList.of("increment_int", "increment_uint"), + new Object[] {1.0, 1.0}); + assertThat(overload).isEmpty(); + } + + @Test + public void findOverload_badInput_throwsException() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from( + "increment_uint", + UnsignedLong.class, + (arg) -> { + if (arg.equals(UnsignedLong.MAX_VALUE)) { + throw new CelEvaluationException( + "numeric overflow", null, CelErrorCode.NUMERIC_OVERFLOW); + } + return arg.plus(UnsignedLong.ONE); + })); + Optional overload = + bindings.findOverload( + "increment", ImmutableList.of("increment_uint"), new Object[] {UnsignedLong.MAX_VALUE}); + assertThat(overload).isPresent(); + assertThat(overload.get().getOverloadId()).isEqualTo("increment_uint"); + assertThat(overload.get().getParameterTypes()).containsExactly(UnsignedLong.class); + InterpreterException e = + Assert.assertThrows( + InterpreterException.class, + () -> overload.get().getDefinition().apply(new Object[] {UnsignedLong.MAX_VALUE})); + assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.NUMERIC_OVERFLOW); + } + + @Test + public void findOverload_multipleMatchingFunctions_throwsException() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("increment_int", Long.class, (arg) -> arg + 1), + CelFunctionBinding.from("increment_uint", Long.class, (arg) -> arg + 2)); + InterpreterException e = + Assert.assertThrows( + InterpreterException.class, + () -> + bindings.findOverload( + "increment", + ImmutableList.of("increment_int", "increment_uint"), + new Object[] {1L})); + assertThat(e).hasMessageThat().contains("Ambiguous overloads for function 'increment'"); + } + + @Test + public void findOverload_nullPrimitiveArg_isEmpty() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("identity_int", Long.class, (arg) -> arg)); + Optional overload = + bindings.findOverload("identity", ImmutableList.of("identity_int"), new Object[] {null}); + assertThat(overload).isEmpty(); + } + + @Test + public void findOverload_nullMessageArg_returnsOverload() throws CelException { + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("identity_msg", TestAllTypes.class, (arg) -> arg)); + Optional overload = + bindings.findOverload("identity", ImmutableList.of("identity_msg"), new Object[] {null}); + assertThat(overload).isPresent(); + assertThat(overload.get().getOverloadId()).isEqualTo("identity_msg"); + assertThat(overload.get().getParameterTypes()).containsExactly(TestAllTypes.class); + assertThat(overload.get().getDefinition().apply(new Object[] {null})).isNull(); + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/CelResolvedOverloadTest.java b/runtime/src/test/java/dev/cel/runtime/CelResolvedOverloadTest.java new file mode 100644 index 000000000..8b0fd7193 --- /dev/null +++ b/runtime/src/test/java/dev/cel/runtime/CelResolvedOverloadTest.java @@ -0,0 +1,67 @@ +// 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.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link CelResolvedOverload}. */ +@RunWith(JUnit4.class) +public final class CelResolvedOverloadTest { + + CelResolvedOverload getIncrementIntOverload() { + return CelResolvedOverload.of( + "increment_int", + ImmutableList.of(Long.class), + (args) -> { + Long arg = (Long) args[0]; + return arg + 1; + }); + } + + @Test + public void canHandle_matchingTypes_returnsTrue() { + assertThat(getIncrementIntOverload().canHandle(new Object[] {1L})).isTrue(); + } + + @Test + public void canHandle_nullMessageType_returnsTrue() { + CelResolvedOverload overload = + CelResolvedOverload.of("identity", ImmutableList.of(TestAllTypes.class), (args) -> args[0]); + assertThat(overload.canHandle(new Object[] {null})).isTrue(); + } + + @Test + public void canHandle_nullPrimitive_returnsFalse() { + CelResolvedOverload overload = + CelResolvedOverload.of("identity", ImmutableList.of(Long.class), (args) -> args[0]); + assertThat(overload.canHandle(new Object[] {null})).isFalse(); + } + + @Test + public void canHandle_nonMatchingTypes_returnsFalse() { + assertThat(getIncrementIntOverload().canHandle(new Object[] {1.0})).isFalse(); + } + + @Test + public void canHandle_nonMatchingArgCount_returnsFalse() { + assertThat(getIncrementIntOverload().canHandle(new Object[] {1L, 2L})).isFalse(); + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java index 5aecde577..f4790cd42 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java @@ -16,10 +16,10 @@ 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.expr.conformance.proto3.TestAllTypes; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import org.junit.Assert; import org.junit.Test; @@ -68,6 +68,8 @@ public void toRuntimeBuilder_collectionProperties_copied() { celRuntimeBuilder.addFileTypes(TestAllTypes.getDescriptor().getFile()); celRuntimeBuilder.addFunctionBindings(CelFunctionBinding.from("test", Integer.class, arg -> 1)); celRuntimeBuilder.addLibraries(runtimeBuilder -> {}); + int originalFileTypesSize = + ((CelRuntimeLegacyImpl.Builder) celRuntimeBuilder).getFileTypes().build().size(); CelRuntimeLegacyImpl celRuntime = (CelRuntimeLegacyImpl) celRuntimeBuilder.build(); CelRuntimeLegacyImpl.Builder newRuntimeBuilder = @@ -75,7 +77,7 @@ public void toRuntimeBuilder_collectionProperties_copied() { assertThat(newRuntimeBuilder.getFunctionBindings()).hasSize(1); assertThat(newRuntimeBuilder.getRuntimeLibraries().build()).hasSize(1); - assertThat(newRuntimeBuilder.getFileTypes().build()).hasSize(8); + assertThat(newRuntimeBuilder.getFileTypes().build()).hasSize(originalFileTypesSize); } @Test diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 867a8ea06..0bba632b4 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -17,7 +17,6 @@ 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; @@ -46,8 +45,13 @@ import dev.cel.common.types.StructTypeReference; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.parser.CelStandardMacro; import dev.cel.parser.CelUnparserFactory; +import dev.cel.policy.CelPolicyConfig; +import dev.cel.policy.CelPolicyConfigParser; +import dev.cel.policy.CelPolicyParserFactory; +import dev.cel.runtime.CelRuntime.CelFunctionBinding; import java.util.List; import java.util.Map; import java.util.Optional; @@ -58,6 +62,9 @@ @RunWith(TestParameterInjector.class) public class CelRuntimeTest { + private static final CelPolicyConfigParser POLICY_CONFIG_PARSER = + CelPolicyParserFactory.newYamlConfigParser(); + @Test public void evaluate_anyPackedEqualityUsingProtoDifferencer_success() throws Exception { Cel cel = @@ -93,6 +100,37 @@ public void evaluate_anyPackedEqualityUsingProtoDifferencer_success() throws Exc assertThat(evaluatedResult).isEqualTo(true); } + @Test + public void evaluate_callExprWithLateBindings_success() throws Exception { + String configSource = + "name: late_bound_function_config\n" + + "functions:\n" + + " - name: 'test'\n" + + " overloads:\n" + + " - id: 'test_bool'\n" + + " args:\n" + + " - type_name: 'bool'\n" + + " return:\n" + + " type_name: 'bool'"; + CelPolicyConfig celPolicyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel celDetails = + CelFactory.standardCelBuilder() + .addVar("a", SimpleType.INT) + .addVar("b", SimpleType.INT) + .addVar("c", SimpleType.INT) + .build(); + Cel cel = celPolicyConfig.extend(celDetails, CelOptions.DEFAULT); + CelAbstractSyntaxTree ast = cel.compile("a < 0 && b < 0 && c < 0 && test(a<0)").getAst(); + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("test_bool", Boolean.class, result -> result)); + + boolean result = + (boolean) cel.createProgram(ast).eval(ImmutableMap.of("a", -1, "b", -1, "c", -4), bindings); + + assertThat(result).isTrue(); + } + @Test public void evaluate_v1alpha1CheckedExpr() throws Exception { // Note: v1alpha1 proto support exists only to help migrate existing consumers. @@ -237,6 +275,52 @@ public void trace_callExpr_identifyFalseBranch() throws Exception { assertThat(CelUnparserFactory.newUnparser().unparse(subtree)).isEqualTo("b < 0"); } + @Test + public void trace_callExprWithLateBindings_identifyFalseBranch() throws Exception { + AtomicReference capturedExpr = new AtomicReference<>(); + CelEvaluationListener listener = + (expr, res) -> { + if (res instanceof Boolean && !(boolean) res && capturedExpr.get() == null) { + capturedExpr.set(expr); + } + }; + + String configSource = + "name: late_bound_function_config\n" + + "functions:\n" + + " - name: 'test'\n" + + " overloads:\n" + + " - id: 'test_bool'\n" + + " args:\n" + + " - type_name: 'bool'\n" + + " return:\n" + + " type_name: 'bool'"; + + CelPolicyConfig celPolicyConfig = POLICY_CONFIG_PARSER.parse(configSource); + Cel celDetails = + CelFactory.standardCelBuilder() + .addVar("a", SimpleType.INT) + .addVar("b", SimpleType.INT) + .addVar("c", SimpleType.INT) + .build(); + Cel cel = celPolicyConfig.extend(celDetails, CelOptions.DEFAULT); + CelAbstractSyntaxTree ast = cel.compile("a < 0 && b < 0 && c < 0 && test(a<0)").getAst(); + CelLateFunctionBindings bindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from("test_bool", Boolean.class, result -> result)); + + boolean result = + (boolean) + cel.createProgram(ast) + .trace(ImmutableMap.of("a", -1, "b", 1, "c", -4), bindings, listener); + + assertThat(result).isFalse(); + // Demonstrate that "b < 0" is what caused the expression to be false + CelAbstractSyntaxTree subtree = + CelAbstractSyntaxTree.newParsedAst(capturedExpr.get(), CelSource.newBuilder().build()); + assertThat(CelUnparserFactory.newUnparser().unparse(subtree)).isEqualTo("b < 0"); + } + @Test public void trace_constant() throws Exception { CelEvaluationListener listener = @@ -279,7 +363,7 @@ public void trace_select() throws Exception { Cel cel = CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .build(); CelAbstractSyntaxTree ast = cel.compile("TestAllTypes{single_int64: 3}.single_int64").getAst(); @@ -298,7 +382,7 @@ public void trace_struct() throws Exception { Cel cel = CelFactory.standardCelBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer("google.api.expr.test.v1.proto3") + .setContainer("cel.expr.conformance.proto3") .build(); CelAbstractSyntaxTree ast = cel.compile("TestAllTypes{}").getAst(); @@ -683,6 +767,6 @@ public void standardEnvironmentDisabledForRuntime_throws() throws Exception { assertThrows(CelEvaluationException.class, () -> celRuntime.createProgram(ast).eval()); assertThat(e) .hasMessageThat() - .contains("Unknown overload id 'size_string' for function 'size'"); + .contains("No matching overload for function 'size'. Overload candidates: size_string"); } } diff --git a/runtime/src/test/java/dev/cel/runtime/CelStandardFunctionsTest.java b/runtime/src/test/java/dev/cel/runtime/CelStandardFunctionsTest.java new file mode 100644 index 000000000..09da78615 --- /dev/null +++ b/runtime/src/test/java/dev/cel/runtime/CelStandardFunctionsTest.java @@ -0,0 +1,244 @@ +// 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.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.common.collect.ImmutableSet; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import com.google.testing.junit.testparameterinjector.TestParameters; +import dev.cel.common.CelOptions; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.runtime.CelStandardFunctions.StandardFunction; +import dev.cel.runtime.CelStandardFunctions.StandardFunction.Overload.Arithmetic; +import dev.cel.runtime.CelStandardFunctions.StandardOverload; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelStandardFunctionsTest { + + @Test + @TestParameters("{includeFunction: true, excludeFunction: true, filterFunction: true}") + @TestParameters("{includeFunction: true, excludeFunction: true, filterFunction: false}") + @TestParameters("{includeFunction: true, excludeFunction: false, filterFunction: true}") + @TestParameters("{includeFunction: false, excludeFunction: true, filterFunction: true}") + public void standardFunction_moreThanOneFunctionFilterSet_throws( + boolean includeFunction, boolean excludeFunction, boolean filterFunction) { + CelStandardFunctions.Builder builder = CelStandardFunctions.newBuilder(); + if (includeFunction) { + builder.includeFunctions(StandardFunction.ADD); + } + if (excludeFunction) { + builder.excludeFunctions(StandardFunction.SUBTRACT); + } + if (filterFunction) { + builder.filterFunctions((func, over) -> true); + } + + IllegalArgumentException e = assertThrows(IllegalArgumentException.class, builder::build); + assertThat(e) + .hasMessageThat() + .contains( + "You may only populate one of the following builder methods: includeFunctions," + + " excludeFunctions or filterFunctions"); + } + + @Test + public void runtime_standardEnvironmentEnabled_throwsWhenOverridingFunctions() { + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + () -> + CelRuntimeFactory.standardCelRuntimeBuilder() + .setStandardEnvironmentEnabled(true) + .setStandardFunctions( + CelStandardFunctions.newBuilder() + .includeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build()) + .build()); + + assertThat(e) + .hasMessageThat() + .contains( + "setStandardEnvironmentEnabled must be set to false to override standard" + + " function bindings"); + } + + @Test + public void standardFunctions_includeFunctions() { + CelStandardFunctions celStandardFunctions = + CelStandardFunctions.newBuilder() + .includeFunctions( + CelStandardFunctions.StandardFunction.ADD, + CelStandardFunctions.StandardFunction.SUBTRACT) + .build(); + + assertThat(celStandardFunctions.getOverloads()) + .containsExactlyElementsIn( + ImmutableSet.builder() + .addAll(CelStandardFunctions.StandardFunction.ADD.getOverloads()) + .addAll(CelStandardFunctions.StandardFunction.SUBTRACT.getOverloads()) + .build()); + } + + @Test + public void standardFunctions_excludeFunctions() { + CelStandardFunctions celStandardFunction = + CelStandardFunctions.newBuilder() + .excludeFunctions( + CelStandardFunctions.StandardFunction.ADD, + CelStandardFunctions.StandardFunction.SUBTRACT) + .build(); + + assertThat(celStandardFunction.getOverloads()) + .doesNotContain(CelStandardFunctions.StandardFunction.ADD.getOverloads()); + assertThat(celStandardFunction.getOverloads()) + .doesNotContain(CelStandardFunctions.StandardFunction.SUBTRACT.getOverloads()); + } + + @Test + public void standardFunctions_filterFunctions() { + CelStandardFunctions celStandardFunction = + CelStandardFunctions.newBuilder() + .filterFunctions( + (func, over) -> { + if (func.equals(CelStandardFunctions.StandardFunction.ADD) + && over.equals(Arithmetic.ADD_INT64)) { + return true; + } + + if (func.equals(CelStandardFunctions.StandardFunction.SUBTRACT) + && over.equals(Arithmetic.SUBTRACT_INT64)) { + return true; + } + + return false; + }) + .build(); + + assertThat(celStandardFunction.getOverloads()) + .containsExactly(Arithmetic.ADD_INT64, Arithmetic.SUBTRACT_INT64); + } + + @Test + public void standardEnvironment_subsetEnvironment() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setStandardEnvironmentEnabled(false) + .setStandardFunctions( + CelStandardFunctions.newBuilder() + .includeFunctions(StandardFunction.ADD, StandardFunction.SUBTRACT) + .build()) + .build(); + assertThat(celRuntime.createProgram(celCompiler.compile("1 + 2 - 3").getAst()).eval()) + .isEqualTo(0); + CelEvaluationException e = + assertThrows( + CelEvaluationException.class, + () -> celRuntime.createProgram(celCompiler.compile("1 * 2 / 3").getAst()).eval()); + assertThat(e) + .hasMessageThat() + .contains("No matching overload for function '_*_'. Overload candidates: multiply_int64"); + } + + @Test + @TestParameters("{expression: '1 > 2.0'}") + @TestParameters("{expression: '2.0 > 1'}") + @TestParameters("{expression: '1 > 2u'}") + @TestParameters("{expression: '2u > 1'}") + @TestParameters("{expression: '2u > 1.0'}") + @TestParameters("{expression: '1.0 > 2u'}") + @TestParameters("{expression: '1 >= 2.0'}") + @TestParameters("{expression: '2.0 >= 1'}") + @TestParameters("{expression: '1 >= 2u'}") + @TestParameters("{expression: '2u >= 1'}") + @TestParameters("{expression: '2u >= 1.0'}") + @TestParameters("{expression: '1.0 >= 2u'}") + @TestParameters("{expression: '1 < 2.0'}") + @TestParameters("{expression: '2.0 < 1'}") + @TestParameters("{expression: '1 < 2u'}") + @TestParameters("{expression: '2u < 1'}") + @TestParameters("{expression: '2u < 1.0'}") + @TestParameters("{expression: '1.0 < 2u'}") + @TestParameters("{expression: '1 <= 2.0'}") + @TestParameters("{expression: '2.0 <= 1'}") + @TestParameters("{expression: '1 <= 2u'}") + @TestParameters("{expression: '2u <= 1'}") + @TestParameters("{expression: '2u <= 1.0'}") + @TestParameters("{expression: '1.0 <= 2u'}") + public void heterogeneousEqualityDisabled_mixedTypeComparisons_throws(String expression) { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableHeterogeneousNumericComparisons(true).build()) + .build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableHeterogeneousNumericComparisons(false).build()) + .build(); + + CelEvaluationException e = + assertThrows( + CelEvaluationException.class, + () -> celRuntime.createProgram(celCompiler.compile(expression).getAst()).eval()); + assertThat(e).hasMessageThat().contains("No matching overload for function"); + } + + @Test + public void unsignedLongsDisabled_int64Identity_throws() { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableUnsignedLongs(true).build()) + .build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableUnsignedLongs(false).build()) + .build(); + + CelEvaluationException e = + assertThrows( + CelEvaluationException.class, + () -> celRuntime.createProgram(celCompiler.compile("int(1)").getAst()).eval()); + assertThat(e) + .hasMessageThat() + .contains("No matching overload for function 'int'. Overload candidates: int64_to_int64"); + } + + @Test + public void timestampEpochDisabled_int64Identity_throws() { + CelCompiler celCompiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setOptions(CelOptions.current().enableTimestampEpoch(true).build()) + .build(); + CelRuntime celRuntime = + CelRuntimeFactory.standardCelRuntimeBuilder() + .setOptions(CelOptions.current().enableTimestampEpoch(false).build()) + .build(); + + CelEvaluationException e = + assertThrows( + CelEvaluationException.class, + () -> + celRuntime.createProgram(celCompiler.compile("timestamp(10000)").getAst()).eval()); + assertThat(e) + .hasMessageThat() + .contains( + "No matching overload for function 'timestamp'. Overload candidates:" + + " int64_to_timestamp"); + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/CelTypeResolverTest.java b/runtime/src/test/java/dev/cel/runtime/CelTypeResolverTest.java new file mode 100644 index 000000000..1d94ac86e --- /dev/null +++ b/runtime/src/test/java/dev/cel/runtime/CelTypeResolverTest.java @@ -0,0 +1,170 @@ +// 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.truth.Truth.assertThat; + +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 dev.cel.bundle.Cel; +import dev.cel.bundle.CelFactory; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelOptions; +import dev.cel.common.types.OpaqueType; +import dev.cel.common.types.OptionalType; +import dev.cel.common.types.ProtoMessageTypeProvider; +import dev.cel.common.types.SimpleType; +import dev.cel.common.types.StructTypeReference; +import dev.cel.common.types.TypeType; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.extensions.CelOptionalLibrary; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class CelTypeResolverTest { + + private static final ProtoMessageTypeProvider PROTO_MESSAGE_TYPE_PROVIDER = + new ProtoMessageTypeProvider(ImmutableList.of(TestAllTypes.getDescriptor())); + + private static final Cel CEL = + CelFactory.standardCelBuilder() + .setOptions(CelOptions.current().enableTimestampEpoch(true).build()) + .setTypeProvider(PROTO_MESSAGE_TYPE_PROVIDER) + .addCompilerLibraries(CelOptionalLibrary.INSTANCE) + .addRuntimeLibraries(CelOptionalLibrary.INSTANCE) + .addMessageTypes(TestAllTypes.getDescriptor()) + .setContainer(TestAllTypes.getDescriptor().getFullName()) + .build(); + + @SuppressWarnings("ImmutableEnumChecker") // Test only + private enum TypeLiteralTestCase { + BOOL("bool", TypeType.create(SimpleType.BOOL)), + BYTES("bytes", TypeType.create(SimpleType.BYTES)), + DOUBLE("double", TypeType.create(SimpleType.DOUBLE)), + DURATION("google.protobuf.Duration", TypeType.create(SimpleType.DURATION)), + INT("int", TypeType.create(SimpleType.INT)), + STRING("string", TypeType.create(SimpleType.STRING)), + TIMESTAMP("google.protobuf.Timestamp", TypeType.create(SimpleType.TIMESTAMP)), + UINT("uint", TypeType.create(SimpleType.UINT)), + + NULL_TYPE("null_type", TypeType.create(SimpleType.NULL_TYPE)), + OPTIONAL_TYPE("optional_type", TypeType.create(OptionalType.create(SimpleType.DYN))), + PROTO_MESSAGE_TYPE( + "TestAllTypes", + TypeType.create(StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))); + + private final String expression; + + private final TypeType celRuntimeType; + + TypeLiteralTestCase(String expression, TypeType celRuntimeType) { + this.expression = expression; + this.celRuntimeType = celRuntimeType; + } + } + + @Test + public void typeLiteral_success(@TestParameter TypeLiteralTestCase testCase) throws Exception { + if (!testCase.equals(TypeLiteralTestCase.DURATION)) { + return; + } + CelAbstractSyntaxTree ast = CEL.compile(testCase.expression).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(testCase.celRuntimeType); + } + + @Test + public void typeLiteral_wrappedInDyn_success(@TestParameter TypeLiteralTestCase testCase) + throws Exception { + CelAbstractSyntaxTree ast = CEL.compile(String.format("dyn(%s)", testCase.expression)).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(testCase.celRuntimeType); + } + + @Test + public void typeLiteral_equality(@TestParameter TypeLiteralTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile(String.format("type(%s) == type", testCase.expression)).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(true); + } + + @SuppressWarnings("ImmutableEnumChecker") // Test only + private enum TypeCallTestCase { + ANY( + "google.protobuf.Any{type_url: 'types.googleapis.com/google.protobuf.DoubleValue'}", + TypeType.create(SimpleType.DOUBLE)), + BOOL("true", TypeType.create(SimpleType.BOOL)), + BYTES("b'hi'", TypeType.create(SimpleType.BYTES)), + DOUBLE("1.5", TypeType.create(SimpleType.DOUBLE)), + DURATION("duration('1h')", TypeType.create(SimpleType.DURATION)), + INT("1", TypeType.create(SimpleType.INT)), + STRING("'test'", TypeType.create(SimpleType.STRING)), + TIMESTAMP("timestamp(123)", TypeType.create(SimpleType.TIMESTAMP)), + UINT("1u", TypeType.create(SimpleType.UINT)), + PROTO_MESSAGE( + "TestAllTypes{}", + TypeType.create(StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))), + OPTIONAL_TYPE("optional.of(1)", TypeType.create(OptionalType.create(SimpleType.DYN))); + + private final String expression; + + private final TypeType celRuntimeType; + + TypeCallTestCase(String expression, TypeType celRuntimeType) { + this.expression = expression; + this.celRuntimeType = celRuntimeType; + } + } + + @Test + public void typeCall_success(@TestParameter TypeCallTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile(String.format("type(%s)", testCase.expression)).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(testCase.celRuntimeType); + } + + @Test + public void typeOfTypeCall_success(@TestParameter TypeCallTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile(String.format("type(type(%s))", testCase.expression)).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(TypeType.create(SimpleType.DYN)); + } + + @Test + public void typeCall_wrappedInDyn_evaluatesToUnderlyingType( + @TestParameter TypeCallTestCase testCase) throws Exception { + CelAbstractSyntaxTree ast = + CEL.compile(String.format("type(dyn(%s))", testCase.expression)).getAst(); + + assertThat(CEL.createProgram(ast).eval()).isEqualTo(testCase.celRuntimeType); + } + + @Test + public void typeCall_opaqueVar() throws Exception { + OpaqueType opaqueType = OpaqueType.create("opaque_type"); + Cel cel = CEL.toCelBuilder().addVar("opaque_var", opaqueType).build(); + CelAbstractSyntaxTree ast = cel.compile("type(opaque_var)").getAst(); + final class CustomClass {} + + assertThat(CEL.createProgram(ast).eval(ImmutableMap.of("opaque_var", new CustomClass()))) + .isEqualTo(TypeType.create(opaqueType)); + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/DefaultDispatcherTest.java b/runtime/src/test/java/dev/cel/runtime/DefaultDispatcherTest.java new file mode 100644 index 000000000..0f34e9fe4 --- /dev/null +++ b/runtime/src/test/java/dev/cel/runtime/DefaultDispatcherTest.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 aj +// +// 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.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link DefaultDispatcher}. */ +@RunWith(JUnit4.class) +public final class DefaultDispatcherTest { + + private Map overloads; + + @Before + public void setup() { + overloads = new HashMap<>(); + overloads.put( + "overload_1", + CelResolvedOverload.of( + "overload_1", new Class[] {Long.class}, args -> (Long) args[0] + 1)); + overloads.put( + "overload_2", + CelResolvedOverload.of( + "overload_2", new Class[] {Long.class}, args -> (Long) args[0] + 2)); + } + + @Test + public void findOverload_multipleMatches_throwsException() { + InterpreterException e = + Assert.assertThrows( + InterpreterException.class, + () -> + DefaultDispatcher.findOverload( + "overloads", + ImmutableList.of("overload_1", "overload_2"), + overloads, + new Object[] {1L})); + assertThat(e).hasMessageThat().contains("Matching candidates: overload_1, overload_2"); + } +} diff --git a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java index c4622a7ab..b9092dd9e 100644 --- a/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java +++ b/runtime/src/test/java/dev/cel/runtime/DescriptorMessageProviderTest.java @@ -17,10 +17,6 @@ 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; @@ -42,6 +38,10 @@ // CEL-Internal-3 import dev.cel.common.internal.ProtoMessageFactory; import dev.cel.common.internal.WellKnownProto; +import dev.cel.expr.conformance.proto2.TestAllTypes; +import dev.cel.expr.conformance.proto2.TestAllTypes.NestedGroup; +import dev.cel.expr.conformance.proto2.TestAllTypesExtensions; +import dev.cel.expr.conformance.proto2.TestAllTypesProto; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -57,7 +57,7 @@ public void setUp() { CelOptions options = CelOptions.current().build(); CelDescriptors celDescriptors = CelDescriptorUtil.getAllDescriptorsFromFileDescriptor( - TestAllTypes.getDescriptor().getFile()); + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFile()); ProtoMessageFactory dynamicMessageFactory = DefaultMessageFactory.create(DefaultDescriptorPool.create(celDescriptors)); provider = new DescriptorMessageProvider(dynamicMessageFactory, options); @@ -65,31 +65,38 @@ public void setUp() { @Test public void createMessage_success() { - TestAllTypes message = - (TestAllTypes) + dev.cel.expr.conformance.proto3.TestAllTypes message = + (dev.cel.expr.conformance.proto3.TestAllTypes) provider.createMessage( - TestAllTypes.getDescriptor().getFullName(), ImmutableMap.of("single_int32", 1)); - assertThat(message).isEqualTo(TestAllTypes.newBuilder().setSingleInt32(1).build()); + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFullName(), + ImmutableMap.of("single_int32", 1)); + assertThat(message) + .isEqualTo( + dev.cel.expr.conformance.proto3.TestAllTypes.newBuilder().setSingleInt32(1).build()); } @Test public void createMessageDynamic_success() { - ImmutableList descriptors = ImmutableList.of(TestAllTypes.getDescriptor()); + ImmutableList descriptors = + ImmutableList.of(dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor()); provider = DynamicMessageFactory.typeProvider(descriptors); Message message = (Message) provider.createMessage( - TestAllTypes.getDescriptor().getFullName(), ImmutableMap.of("single_int32", 1)); - assertThat(message).isInstanceOf(TestAllTypes.class); - assertThat(message).isEqualTo(TestAllTypes.newBuilder().setSingleInt32(1).build()); + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFullName(), + ImmutableMap.of("single_int32", 1)); + assertThat(message).isInstanceOf(dev.cel.expr.conformance.proto3.TestAllTypes.class); + assertThat(message) + .isEqualTo( + dev.cel.expr.conformance.proto3.TestAllTypes.newBuilder().setSingleInt32(1).build()); } @Test public void createNestedGroup_success() throws Exception { - String groupType = "google.api.expr.test.v1.proto2.TestAllTypes.NestedGroup"; + String groupType = "cel.expr.conformance.proto2.TestAllTypes.NestedGroup"; provider = DynamicMessageFactory.typeProvider( - ImmutableList.of(TestAllTypesProto.TestAllTypes.NestedGroup.getDescriptor())); + ImmutableList.of(TestAllTypes.NestedGroup.getDescriptor())); Message message = (Message) provider.createMessage( @@ -113,10 +120,10 @@ public void createMessage_missingDescriptorError() { @Test public void createMessage_unsetWrapperField() { - TestAllTypes message = - (TestAllTypes) + dev.cel.expr.conformance.proto3.TestAllTypes message = + (dev.cel.expr.conformance.proto3.TestAllTypes) provider.createMessage( - TestAllTypes.getDescriptor().getFullName(), + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFullName(), ImmutableMap.of("single_int64_wrapper", NullValue.NULL_VALUE)); assertThat(message).isEqualToDefaultInstance(); } @@ -127,7 +134,7 @@ public void createMessage_badFieldError() { IllegalArgumentException.class, () -> provider.createMessage( - TestAllTypes.getDescriptor().getFullName(), + dev.cel.expr.conformance.proto3.TestAllTypes.getDescriptor().getFullName(), ImmutableMap.of("bad_field", NullValue.NULL_VALUE))); } @@ -157,7 +164,10 @@ public void selectField_mapKeyNotFound() { @Test public void selectField_unsetWrapperField() { - assertThat(provider.selectField(TestAllTypes.getDefaultInstance(), "single_int64_wrapper")) + assertThat( + provider.selectField( + dev.cel.expr.conformance.proto3.TestAllTypes.getDefaultInstance(), + "single_int64_wrapper")) .isEqualTo(NullValue.NULL_VALUE); } @@ -184,9 +194,7 @@ public void selectField_extensionUsingDynamicTypes() { long result = (long) provider.selectField( - TestAllTypesProto.TestAllTypes.newBuilder() - .setExtension(TestAllTypesExtensions.int32Ext, 10) - .build(), + TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 10).build(), 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 b19434ff1..bead31569 100644 --- a/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java +++ b/runtime/src/test/java/dev/cel/runtime/MessageFactoryTest.java @@ -16,9 +16,9 @@ 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.expr.conformance.proto3.TestAllTypes; import dev.cel.runtime.MessageFactory.CombinedMessageFactory; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java b/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java index b75015213..0418c0c49 100644 --- a/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java +++ b/runtime/src/test/java/dev/cel/runtime/RuntimeEqualityTest.java @@ -70,12 +70,11 @@ public final class RuntimeEqualityTest { .enableProtoDifferencerEquality(true) .build(); private static final CelOptions UNSIGNED_LONGS = - CelOptions.newBuilder().disableCelStandardEquality(false).enableUnsignedLongs(true).build(); + CelOptions.newBuilder().disableCelStandardEquality(false).build(); private static final CelOptions PROTO_EQUALITY_UNSIGNED_LONGS = CelOptions.newBuilder() .disableCelStandardEquality(false) .enableProtoDifferencerEquality(true) - .enableUnsignedLongs(true) .build(); private static final RuntimeEquality RUNTIME_EQUALITY = 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 cbbf32e04..54f2a1c42 100644 --- a/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/async/BUILD.bazel @@ -10,7 +10,7 @@ java_library( testonly = True, srcs = glob(["*Test.java"]), deps = [ - "//:java_truth", + # "//java/com/google/testing/testsize:annotations", "//bundle:cel", "//common", "//common:options", @@ -20,18 +20,20 @@ java_library( "//runtime:unknown_attributes", "//runtime:unknown_options", "//runtime/async", + "@maven//:junit_junit", + "@maven//:com_google_testparameterinjector_test_parameter_injector", + "//:java_truth", "@cel_spec//proto/cel/expr:expr_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto", "@maven//:com_google_guava_guava", - "@maven//:com_google_testparameterinjector_test_parameter_injector", - "@maven//:junit_junit", ], ) junit4_test_suites( name = "test_suites", + shard_count = 4, sizes = [ - "small", + "medium", ], src_dir = "src/test/java", deps = [":tests"], 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 fc9fcc3e4..b6675f75c 100644 --- a/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/async/CelAsyncRuntimeImplTest.java @@ -23,17 +23,18 @@ 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; import com.google.testing.junit.testparameterinjector.TestParameterInjector; +// import com.google.testing.testsize.MediumTest; import dev.cel.bundle.Cel; import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; import dev.cel.common.testing.RepeatedTestProvider; import dev.cel.common.types.SimpleType; +import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.runtime.CelAttributeParser; import dev.cel.runtime.CelAttributePattern; import dev.cel.runtime.CelEvaluationException; @@ -48,6 +49,7 @@ import org.junit.runner.RunWith; @RunWith(TestParameterInjector.class) +// @MediumTest public final class CelAsyncRuntimeImplTest { @Test diff --git a/runtime/src/test/resources/BUILD.bazel b/runtime/src/test/resources/BUILD.bazel index 73b85b496..e419ff319 100644 --- a/runtime/src/test/resources/BUILD.bazel +++ b/runtime/src/test/resources/BUILD.bazel @@ -9,20 +9,3 @@ filegroup( name = "resources", srcs = glob(["*.baseline"]), ) - -java_proto_library( - name = "test_java_proto", - deps = [":test_proto"], -) - -proto_library( - name = "test_proto", - srcs = glob(["*.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", - ], -) diff --git a/runtime/src/test/resources/dynamicMessage_adapted.baseline b/runtime/src/test/resources/dynamicMessage_adapted.baseline index d4e7b12b2..789a39488 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -64,11 +64,11 @@ result: bb: 42 Source: msg.single_bool_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -127,11 +127,11 @@ result: true Source: msg.single_bytes_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -190,11 +190,11 @@ result: hi Source: msg.single_double_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -253,11 +253,11 @@ result: -3.0 Source: msg.single_float_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -316,11 +316,11 @@ result: 1.5 Source: msg.single_int32_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -379,11 +379,11 @@ result: -12 Source: msg.single_int64_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -442,11 +442,11 @@ result: -34 Source: msg.single_string_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -505,11 +505,11 @@ result: hello Source: msg.single_uint32_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -568,11 +568,11 @@ result: 12 Source: msg.single_uint64_wrapper declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -631,11 +631,11 @@ result: 34 Source: msg.single_duration declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -696,11 +696,11 @@ nanos: 20 Source: msg.single_timestamp declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -761,11 +761,11 @@ nanos: 200 Source: msg.single_value declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -824,11 +824,11 @@ result: a Source: msg.single_struct declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { @@ -887,11 +887,11 @@ result: {b=c} Source: msg.list_value declare msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {msg=single_any { - type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage" + type_url: "type.googleapis.com/cel.expr.conformance.proto3.TestAllTypes.NestedMessage" value: "\b*" } single_duration { diff --git a/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline b/runtime/src/test/resources/dynamicMessage_dynamicDescriptor.baseline index 5d30b1fec..36dac04c3 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> -bindings: {any_packed_test_msg=type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes" +bindings: {any_packed_test_msg=type_url: "type.googleapis.com/cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare test_msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare test_msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare test_msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare test_msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes } declare f_msg { - function f_msg_generated (google.api.expr.test.v1.proto3.TestAllTypes) -> bool + function f_msg_generated (cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare test_msg { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare dynamic_msg { value dev.cel.testing.testdata.serialized.proto3.TestAllTypes } declare f_msg { - function f_msg_generated (google.api.expr.test.v1.proto3.TestAllTypes) -> bool + function f_msg_generated (cel.expr.conformance.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 50f7897e0..00e2bba9c 100644 --- a/runtime/src/test/resources/extensionManipulation.baseline +++ b/runtime/src/test/resources/extensionManipulation.baseline @@ -9,54 +9,54 @@ Source: [y.hasI(), y.getI() == 200, !n.hasI(), n.getI() == 0, n.assignR(["a", "b"].map(s, TestAllTypes{single_string:s})).getR().map(h, h.single_string) == ["a", "b"], y.clearR().getR() == []] declare y { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto2.TestAllTypes } declare n { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto2.TestAllTypes } declare getI { - function getI google.api.expr.test.v1.proto3.TestAllTypes.() -> int + function getI cel.expr.conformance.proto2.TestAllTypes.() -> int } declare hasI { - function hasI google.api.expr.test.v1.proto3.TestAllTypes.() -> bool + function hasI cel.expr.conformance.proto2.TestAllTypes.() -> bool } declare assignI { - function assignI google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignI cel.expr.conformance.proto2.TestAllTypes.(int) -> cel.expr.conformance.proto2.TestAllTypes } declare clearI { - function clearI google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes + function clearI cel.expr.conformance.proto2.TestAllTypes.() -> cel.expr.conformance.proto2.TestAllTypes } declare getN { - function getN google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes + function getN cel.expr.conformance.proto2.TestAllTypes.() -> cel.expr.conformance.proto2.TestAllTypes } declare hasN { - function hasN google.api.expr.test.v1.proto3.TestAllTypes.() -> bool + function hasN cel.expr.conformance.proto2.TestAllTypes.() -> bool } declare assignN { - function assignN google.api.expr.test.v1.proto3.TestAllTypes.(google.api.expr.test.v1.proto3.TestAllTypes) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignN cel.expr.conformance.proto2.TestAllTypes.(cel.expr.conformance.proto2.TestAllTypes) -> cel.expr.conformance.proto2.TestAllTypes } declare clearN { - function clearN google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes + function clearN cel.expr.conformance.proto2.TestAllTypes.() -> cel.expr.conformance.proto2.TestAllTypes } declare getR { - function getR google.api.expr.test.v1.proto3.TestAllTypes.() -> list(google.api.expr.test.v1.proto2.TestAllTypes) + function getR cel.expr.conformance.proto2.TestAllTypes.() -> list(cel.expr.conformance.proto2.TestAllTypes) } declare assignR { - function assignR google.api.expr.test.v1.proto3.TestAllTypes.(list(google.api.expr.test.v1.proto2.TestAllTypes)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignR cel.expr.conformance.proto2.TestAllTypes.(list(cel.expr.conformance.proto2.TestAllTypes)) -> cel.expr.conformance.proto2.TestAllTypes } declare clearR { - function clearR google.api.expr.test.v1.proto3.TestAllTypes.() -> google.api.expr.test.v1.proto3.TestAllTypes + function clearR cel.expr.conformance.proto2.TestAllTypes.() -> cel.expr.conformance.proto2.TestAllTypes } =====> bindings: {y=single_int32: 100 -[google.api.expr.test.v1.proto2.int32_ext]: 200 -[google.api.expr.test.v1.proto2.nested_ext] { +[cel.expr.conformance.proto2.int32_ext]: 200 +[cel.expr.conformance.proto2.nested_ext] { single_int32: 50 } -[google.api.expr.test.v1.proto2.repeated_test_all_types] { +[cel.expr.conformance.proto2.repeated_test_all_types] { single_string: "alpha" } -[google.api.expr.test.v1.proto2.repeated_test_all_types] { +[cel.expr.conformance.proto2.repeated_test_all_types] { single_string: "alpha" } , n=single_int32: 50 diff --git a/runtime/src/test/resources/fieldManipulation.baseline b/runtime/src/test/resources/fieldManipulation.baseline index 7734ee7f4..bda3bcac6 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 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -100,19 +100,19 @@ result: true Source: singletonInt64(12) == TestAllTypes{single_int64: 12} declare assignSingleInt64 { - function assignSingleInt64 google.api.expr.test.v1.proto3.TestAllTypes.(int) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignSingleInt64 cel.expr.conformance.proto3.TestAllTypes.(int) -> cel.expr.conformance.proto3.TestAllTypes } declare assignRepeatedInt64 { - function assignRepeatedInt64 google.api.expr.test.v1.proto3.TestAllTypes.(list(int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignRepeatedInt64 cel.expr.conformance.proto3.TestAllTypes.(list(int)) -> cel.expr.conformance.proto3.TestAllTypes } declare assignMap { - function assignMap google.api.expr.test.v1.proto3.TestAllTypes.(map(int, int)) -> google.api.expr.test.v1.proto3.TestAllTypes + function assignMap cel.expr.conformance.proto3.TestAllTypes.(map(int, int)) -> cel.expr.conformance.proto3.TestAllTypes } declare clearField { - function clearField google.api.expr.test.v1.proto3.TestAllTypes.(string) -> google.api.expr.test.v1.proto3.TestAllTypes + function clearField cel.expr.conformance.proto3.TestAllTypes.(string) -> cel.expr.conformance.proto3.TestAllTypes } declare singletonInt64 { - function singletonInt64 (int) -> google.api.expr.test.v1.proto3.TestAllTypes + function singletonInt64 (int) -> cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} diff --git a/runtime/src/test/resources/has.baseline b/runtime/src/test/resources/has.baseline index 3a32d3389..a98f2474f 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_int32: 1 diff --git a/runtime/src/test/resources/jsonValueTypes.baseline b/runtime/src/test/resources/jsonValueTypes.baseline index 9a116c090..ff406cf94 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -11,7 +11,7 @@ result: true Source: x.single_value == double(1) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -22,7 +22,7 @@ result: true Source: x.single_value == 1.1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -33,7 +33,7 @@ result: true Source: x.single_value == null declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -44,7 +44,7 @@ result: true Source: x.single_value == 'hello' declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_value { @@ -55,7 +55,7 @@ result: true Source: x.single_value[0] == [['hello'], -1.1][0] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -123,7 +123,7 @@ result: single_struct { Source: pair(x.single_struct.str[0], 'val') declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare pair { function pair (string, string) -> dyn diff --git a/runtime/src/test/resources/lateBoundFunctions.baseline b/runtime/src/test/resources/lateBoundFunctions.baseline new file mode 100644 index 000000000..2ae6bddaa --- /dev/null +++ b/runtime/src/test/resources/lateBoundFunctions.baseline @@ -0,0 +1,7 @@ +Source: record('foo', 'bar') +declare record { + function record_string_dyn (string, dyn) -> dyn +} +=====> +bindings: {} +result: bar diff --git a/runtime/src/test/resources/lists.baseline b/runtime/src/test/resources/lists.baseline index 493b1c60a..865b27a08 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int @@ -56,7 +56,7 @@ result: true Source: !(4 in list) && 1 in list declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int @@ -70,7 +70,7 @@ result: true Source: !(y in list) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int @@ -84,7 +84,7 @@ result: true Source: y in list declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int @@ -98,7 +98,7 @@ result: true Source: list[3] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int diff --git a/runtime/src/test/resources/maps.baseline b/runtime/src/test/resources/maps.baseline index 33c0cd0c7..1e79b815e 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -16,7 +16,7 @@ result: true Source: x.map_int32_int64[22] == 23 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=map_int32_int64 { @@ -48,7 +48,7 @@ result: true Source: !(4 in map) && 1 in map declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int @@ -76,7 +76,7 @@ result: true Source: !(y in map) && (y + 3) in map declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare y { value int diff --git a/runtime/src/test/resources/messages.baseline b/runtime/src/test/resources/messages.baseline index 3a5dcf81b..f870eb0c3 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_nested_message { @@ -11,10 +11,10 @@ result: true Source: single_nested_message.bb == 43 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare single_nested_message { - value google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare single_nested_message { - value google.api.expr.test.v1.proto3.TestAllTypes.NestedMessage + value cel.expr.conformance.proto3.TestAllTypes.NestedMessage } =====> bindings: {} diff --git a/runtime/src/test/resources/namespacedVariables.baseline b/runtime/src/test/resources/namespacedVariables.baseline index 2b58cc41a..9c0db8f0b 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 035a95726..e7e2199bf 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=single_nested_enum: BAR @@ -9,7 +9,7 @@ result: true Source: single_nested_enum == TestAllTypes.NestedEnum.BAR declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 81e9f1a96..0ebfa02ae 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -26,7 +26,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -49,7 +49,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -71,7 +71,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -89,7 +89,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -108,13 +108,13 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) } =====> -bindings: {list=[type_url: "type.googleapis.com/google.api.expr.test.v1.proto3.TestAllTypes" +bindings: {list=[type_url: "type.googleapis.com/cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -153,7 +153,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -175,7 +175,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -197,7 +197,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -218,7 +218,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -239,7 +239,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) @@ -260,7 +260,7 @@ declare d { value google.protobuf.Duration } declare message { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare list { value list(dyn) diff --git a/runtime/src/test/resources/typeComparisons.baseline b/runtime/src/test/resources/typeComparisons.baseline index 915bdf4d9..ae3e8aa01 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{}) == .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 +Source: type(TestAllTypes{}) == TestAllTypes && type(TestAllTypes{}) == proto3.TestAllTypes && type(TestAllTypes{}) == .cel.expr.conformance.proto3.TestAllTypes && type(proto3.TestAllTypes{}) == TestAllTypes && type(proto3.TestAllTypes{}) == proto3.TestAllTypes && type(proto3.TestAllTypes{}) == .cel.expr.conformance.proto3.TestAllTypes && type(.cel.expr.conformance.proto3.TestAllTypes{}) == TestAllTypes && type(.cel.expr.conformance.proto3.TestAllTypes{}) == proto3.TestAllTypes && type(.cel.expr.conformance.proto3.TestAllTypes{}) == .cel.expr.conformance.proto3.TestAllTypes =====> bindings: {} result: true diff --git a/runtime/src/test/resources/unknownField.baseline b/runtime/src/test/resources/unknownField.baseline index 5ddc80da5..c5f3c755a 100644 --- a/runtime/src/test/resources/unknownField.baseline +++ b/runtime/src/test/resources/unknownField.baseline @@ -1,75 +1,55 @@ Source: x.single_int32 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.map_int32_int64[22] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.repeated_nested_message[1] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.single_timestamp.getSeconds() declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.single_nested_message.bb declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: {1: x.single_int32} declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 4 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[4]} Source: [1, x.single_int32] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 3 -} +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} diff --git a/runtime/src/test/resources/unknownResultSet.baseline b/runtime/src/test/resources/unknownResultSet.baseline index 2b2c61f62..65ec7daa8 100644 --- a/runtime/src/test/resources/unknownResultSet.baseline +++ b/runtime/src/test/resources/unknownResultSet.baseline @@ -1,17 +1,14 @@ Source: x.single_int32 == 1 && true declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.single_int32 == 1 && false declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -19,41 +16,31 @@ result: false Source: x.single_int32 == 1 && x.single_int64 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 - exprs: 6 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1, 6]} Source: x.single_int32 == 1 && x.single_timestamp <= timestamp("bad timestamp string") declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: true && x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: false && x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -61,18 +48,15 @@ result: false Source: x.single_timestamp <= timestamp("bad timestamp string") && x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 7 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[7]} Source: x.single_timestamp <= timestamp("bad timestamp string") && x.single_timestamp > timestamp("another bad timestamp string") declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -81,54 +65,39 @@ error_code: BAD_FORMAT Source: x.single_int32 == 1 || x.single_string == "test" declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 - exprs: 6 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1, 6]} Source: x.single_int32 == 1 || x.single_string != "test" declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 - exprs: 6 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1, 6]} Source: x.single_int32 == 1 || x.single_int64 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 - exprs: 6 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1, 6]} Source: x.single_int32 == 1 || x.single_timestamp <= timestamp("bad timestamp string") declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: true || x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -136,29 +105,23 @@ result: true Source: false || x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: x.single_timestamp <= timestamp("bad timestamp string") || x.single_int32 == 1 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} -result: unknown { - exprs: 7 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[7]} Source: x.single_timestamp <= timestamp("bad timestamp string") || x.single_timestamp > timestamp("another bad timestamp string") declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {} @@ -167,50 +130,40 @@ error_code: BAD_FORMAT Source: x.single_int32.f(1) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: 1.f(x.single_int32) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: x.single_int64.f(x.single_int32) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 1 - exprs: 4 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1, 4]} Source: x declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -221,44 +174,33 @@ single_timestamp { seconds: 15 } } -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> -bindings: {x=unknown { -} -} -result: unknown { - exprs: 1 -} - +bindings: {x=CelUnknownSet{attributes=[], unknownExprIds=[1]}} +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: x.map_int32_int64.map(x, x > 0, x + 1) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: [0, 2, 4].exists(z, z == 2 || z == x.single_int32) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -269,106 +211,84 @@ result: true Source: [0, 2, 4].exists(z, z == x.single_int32) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 9 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[9]} Source: [0, 2, 4].exists_one(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 26 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[26]} Source: [0, 2].all(z, z == 2 || z == x.single_int32) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 12 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[12]} Source: [0, 2, 4].filter(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 26 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[26]} Source: [0, 2, 4].map(z, z == 0 || (z == 2 && z == x.single_int32) || (z == 4 && z == x.single_int64)) declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 17 - exprs: 26 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[17, 26]} Source: x.single_int32 == 1 ? 1 : 2 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: true ? x.single_int32 : 2 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: true ? 1 : x.single_int32 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -379,7 +299,7 @@ result: 1 Source: false ? x.single_int32 : 2 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool @@ -390,128 +310,122 @@ result: 2 Source: false ? 1 : x.single_int32 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 4 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[4]} Source: x.single_int64 == 1 ? x.single_int32 : x.single_int32 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 1 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[1]} Source: {x.single_int32: 2, 3: 4} declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: {1: x.single_int32, 3: 4} declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 4 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[4]} Source: {1: x.single_int32, x.single_int64: 4} declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 4 - exprs: 7 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[4, 7]} Source: [1, x.single_int32, 3, 4] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: [1, x.single_int32, x.single_int64, 4] declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 - exprs: 5 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3, 5]} Source: TestAllTypes{single_int32: x.single_int32}.single_int32 == 2 declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 -} - +result: CelUnknownSet{attributes=[], unknownExprIds=[3]} Source: TestAllTypes{single_int32: x.single_int32, single_int64: x.single_int64} declare x { - value google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes +} +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +result: CelUnknownSet{attributes=[], unknownExprIds=[3, 6]} + +Source: type(x.single_int32) +declare x { + value cel.expr.conformance.proto3.TestAllTypes } declare f { function f int.(int) -> bool } =====> bindings: {} -result: unknown { - exprs: 3 - exprs: 6 +result: CelUnknownSet{attributes=[], unknownExprIds=[2]} + +Source: type(1 / 0 > 2) +declare x { + value cel.expr.conformance.proto3.TestAllTypes } +declare f { + function f int.(int) -> bool +} +=====> +bindings: {} +error: evaluation error: / by zero +error_code: DIVIDE_BY_ZERO diff --git a/runtime/src/test/resources/wrappers.baseline b/runtime/src/test/resources/wrappers.baseline index 718130bde..b440e71ac 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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.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 google.api.expr.test.v1.proto3.TestAllTypes + value cel.expr.conformance.proto3.TestAllTypes } =====> bindings: {x=} diff --git a/runtime/testdata/BUILD.bazel b/runtime/testdata/BUILD.bazel index f4bc22608..64758de75 100644 --- a/runtime/testdata/BUILD.bazel +++ b/runtime/testdata/BUILD.bazel @@ -4,11 +4,6 @@ package( default_visibility = ["//visibility:public"], ) -alias( - name = "test_java_proto", - actual = "//runtime/src/test/resources:test_java_proto", -) - alias( name = "testdata", actual = "//runtime/src/test/resources", diff --git a/testing/src/main/java/dev/cel/testing/BUILD.bazel b/testing/src/main/java/dev/cel/testing/BUILD.bazel index be0b8ac69..ec2bcc932 100644 --- a/testing/src/main/java/dev/cel/testing/BUILD.bazel +++ b/testing/src/main/java/dev/cel/testing/BUILD.bazel @@ -53,7 +53,7 @@ java_library( srcs = TEST_DECL_SOURCES, deps = [ "//common:compiler_common", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "//compiler:compiler_builder", "@cel_spec//proto/cel/expr:expr_java_proto", @@ -71,6 +71,7 @@ java_library( "//common", "//common:compiler_common", "//common:options", + "//common/types:cel_proto_types", "//common/types:cel_types", "//common/types:message_type_provider", "//common/types:type_providers", @@ -102,13 +103,15 @@ java_library( "//common/internal:cel_descriptor_pools", "//common/internal:file_descriptor_converter", "//common/resources/testdata/proto3:standalone_global_enum_java_proto", - "//common/types:cel_types", + "//common/types:cel_proto_types", "//common/types:type_providers", "//extensions:optional_library", "//runtime", "//runtime:runtime_helper", + "//runtime:unknown_attributes", "@cel_spec//proto/cel/expr:expr_java_proto", - "@cel_spec//proto/test/v1/proto3:test_all_types_java_proto", + "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_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", diff --git a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java index 68f343a19..a14d359ac 100644 --- a/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java +++ b/testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java @@ -20,19 +20,16 @@ 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.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; 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.errorprone.annotations.Immutable; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -65,18 +62,24 @@ import dev.cel.common.CelProtoAbstractSyntaxTree; import dev.cel.common.internal.DefaultDescriptorPool; import dev.cel.common.internal.FileDescriptorSetConverter; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelTypeProvider; -import dev.cel.common.types.CelTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypes.NestedEnum; +import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage; import dev.cel.extensions.CelOptionalLibrary; import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelLateFunctionBindings; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; +import dev.cel.runtime.CelUnknownSet; 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.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -97,10 +100,8 @@ private static CelOptions.Builder newBaseOptions() { /** 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), + CEL_TYPE(newBaseOptions().build(), true), + PROTO_TYPE(newBaseOptions().build(), false), ; public final CelOptions celOptions; @@ -157,12 +158,17 @@ private Object runTest() { } private Object runTest(CelVariableResolver variableResolver) { - return runTestInternal(variableResolver); + return runTestInternal(variableResolver, Optional.empty()); } /** Helper to run a test for configured instance variables. */ private Object runTest(Map input) { - return runTestInternal(input); + return runTestInternal(input, Optional.empty()); + } + + /** Helper to run a test for configured instance variables. */ + private Object runTest(Map input, CelLateFunctionBindings lateFunctionBindings) { + return runTestInternal(input, Optional.of(lateFunctionBindings)); } /** @@ -170,16 +176,27 @@ private Object runTest(Map input) { * CelVariableResolver}. */ @SuppressWarnings("unchecked") - private Object runTestInternal(Object input) { + private Object runTestInternal( + Object input, Optional lateFunctionBindings) { CelAbstractSyntaxTree ast = compileTestCase(); printBinding(input); Object result = null; try { CelRuntime.Program program = celRuntime.createProgram(ast); - result = - input instanceof Map - ? program.eval(((Map) input)) - : program.eval((CelVariableResolver) input); + if (lateFunctionBindings.isPresent()) { + if (input instanceof Map) { + Map map = ((Map) input); + CelVariableResolver variableResolver = (name) -> Optional.ofNullable(map.get(name)); + result = program.eval(variableResolver, lateFunctionBindings.get()); + } else { + result = program.eval((CelVariableResolver) input, lateFunctionBindings.get()); + } + } else { + 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. @@ -199,11 +216,11 @@ public void arithmInt64() { source = "1 < 2 && 1 <= 1 && 2 > 1 && 1 >= 1 && 1 == 1 && 2 != 1"; runTest(); - declareVariable("x", CelTypes.INT64); + declareVariable("x", CelProtoTypes.INT64); source = "1 + 2 - x * 3 / x + (x % 3)"; runTest(ImmutableMap.of("x", -5L)); - declareVariable("y", CelTypes.DYN); + declareVariable("y", CelProtoTypes.DYN); source = "x + y == 1"; runTest(extend(ImmutableMap.of("x", -5L), ImmutableMap.of("y", 6))); } @@ -238,11 +255,11 @@ public void arithmUInt64() { runTest(); boolean useUnsignedLongs = celOptions.enableUnsignedLongs(); - declareVariable("x", CelTypes.UINT64); + declareVariable("x", CelProtoTypes.UINT64); source = "1u + 2u + x * 3u / x + (x % 3u)"; runTest(ImmutableMap.of("x", useUnsignedLongs ? UnsignedLong.valueOf(5L) : 5L)); - declareVariable("y", CelTypes.DYN); + declareVariable("y", CelProtoTypes.DYN); source = "x + y == 11u"; runTest( extend( @@ -279,11 +296,11 @@ 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(); - declareVariable("x", CelTypes.DOUBLE); + declareVariable("x", CelProtoTypes.DOUBLE); source = "1.0 + 2.3 + x * 3.0 / x"; runTest(ImmutableMap.of("x", 3.33)); - declareVariable("y", CelTypes.DYN); + declareVariable("y", CelProtoTypes.DYN); source = "x + y == 9.99"; runTest(extend(ImmutableMap.of("x", 3.33d), ImmutableMap.of("y", 6.66))); } @@ -312,9 +329,9 @@ public void quantifiers() { @Test public void arithmTimestamp() { container = Type.getDescriptor().getFile().getPackage(); - declareVariable("ts1", CelTypes.TIMESTAMP); - declareVariable("ts2", CelTypes.TIMESTAMP); - declareVariable("d1", CelTypes.DURATION); + declareVariable("ts1", CelProtoTypes.TIMESTAMP); + declareVariable("ts2", CelProtoTypes.TIMESTAMP); + declareVariable("d1", CelProtoTypes.DURATION); 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(); @@ -339,9 +356,9 @@ public void arithmTimestamp() { @Test public void arithmDuration() { container = Type.getDescriptor().getFile().getPackage(); - declareVariable("d1", CelTypes.DURATION); - declareVariable("d2", CelTypes.DURATION); - declareVariable("d3", CelTypes.DURATION); + declareVariable("d1", CelProtoTypes.DURATION); + declareVariable("d2", CelProtoTypes.DURATION); + declareVariable("d3", CelProtoTypes.DURATION); 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(); @@ -379,7 +396,7 @@ public void arithCrossNumericTypes() { @Test public void booleans() { - declareVariable("x", CelTypes.BOOL); + declareVariable("x", CelProtoTypes.BOOL); source = "x ? 1 : 0"; runTest(ImmutableMap.of("x", true)); runTest(ImmutableMap.of("x", false)); @@ -390,7 +407,7 @@ public void booleans() { source = "(1 / 0 == 0 || true) == (true || 1 / 0 == 0)"; runTest(); - declareVariable("y", CelTypes.INT64); + declareVariable("y", CelProtoTypes.INT64); source = "1 / y == 1 || true"; runTest(ImmutableMap.of("y", 0L)); @@ -463,7 +480,7 @@ public void strings() throws Exception { source = "'a' < 'b' && 'a' <= 'b' && 'b' > 'a' && 'a' >= 'a' && 'a' == 'a' && 'a' != 'b'"; runTest(); - declareVariable("x", CelTypes.STRING); + declareVariable("x", CelProtoTypes.STRING); source = "'abc' + x == 'abcdef' && " + "x.endsWith('ef') && " @@ -479,13 +496,13 @@ public void messages() throws Exception { TestAllTypes.newBuilder() .setSingleNestedMessage(NestedMessage.newBuilder().setBb(43)) .build(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "x.single_nested_message.bb == 43 && has(x.single_nested_message)"; runTest(ImmutableMap.of("x", nestedMessage)); declareVariable( "single_nested_message", - CelTypes.createMessage(NestedMessage.getDescriptor().getFullName())); + CelProtoTypes.createMessage(NestedMessage.getDescriptor().getFullName())); source = "single_nested_message.bb == 43"; runTest(ImmutableMap.of("single_nested_message", nestedMessage.getSingleNestedMessage())); @@ -510,7 +527,7 @@ public void optional() { source = "optional.unwrap([])"; runTest(); - declareVariable("str", CelTypes.STRING); + declareVariable("str", CelProtoTypes.STRING); source = "optional.unwrap([optional.none(), optional.of(1), optional.of(str)])"; runTest(ImmutableMap.of("str", "foo")); } @@ -535,7 +552,7 @@ public void has() throws Exception { .putMapInt32Int64(1, 2L) .setSingleNestedMessage(NestedMessage.newBuilder().setBb(43)) .build(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "has(x.single_int32) && !has(x.single_int64) && has(x.single_bool_wrapper)" + " && has(x.single_int32_wrapper) && !has(x.single_int64_wrapper)" @@ -549,8 +566,8 @@ public void has() throws Exception { @Test public void duration() throws Exception { - declareVariable("d1", CelTypes.DURATION); - declareVariable("d2", CelTypes.DURATION); + declareVariable("d1", CelProtoTypes.DURATION); + declareVariable("d2", CelProtoTypes.DURATION); Duration d1010 = Duration.newBuilder().setSeconds(10).setNanos(10).build(); Duration d1009 = Duration.newBuilder().setSeconds(10).setNanos(9).build(); Duration d0910 = Duration.newBuilder().setSeconds(9).setNanos(10).build(); @@ -587,8 +604,8 @@ public void duration() throws Exception { @Test public void timestamp() throws Exception { - declareVariable("t1", CelTypes.TIMESTAMP); - declareVariable("t2", CelTypes.TIMESTAMP); + declareVariable("t1", CelProtoTypes.TIMESTAMP); + declareVariable("t2", CelProtoTypes.TIMESTAMP); Timestamp ts1010 = Timestamp.newBuilder().setSeconds(10).setNanos(10).build(); Timestamp ts1009 = Timestamp.newBuilder().setSeconds(10).setNanos(9).build(); Timestamp ts0910 = Timestamp.newBuilder().setSeconds(9).setNanos(10).build(); @@ -631,10 +648,11 @@ public void packUnpackAny() { return; } container = TestAllTypes.getDescriptor().getFile().getPackage(); - declareVariable("any", CelTypes.ANY); - declareVariable("d", CelTypes.DURATION); - declareVariable("message", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); - declareVariable("list", CelTypes.createList(CelTypes.DYN)); + declareVariable("any", CelProtoTypes.ANY); + declareVariable("d", CelProtoTypes.DURATION); + declareVariable( + "message", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("list", CelProtoTypes.createList(CelProtoTypes.DYN)); Duration duration = Durations.fromSeconds(100); Any any = Any.pack(duration); TestAllTypes message = TestAllTypes.newBuilder().setSingleAny(any).build(); @@ -676,12 +694,12 @@ public void packUnpackAny() { @Test public void nestedEnums() { TestAllTypes nestedEnum = TestAllTypes.newBuilder().setSingleNestedEnum(NestedEnum.BAR).build(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "x.single_nested_enum == TestAllTypes.NestedEnum.BAR"; runTest(ImmutableMap.of("x", nestedEnum)); - declareVariable("single_nested_enum", CelTypes.INT64); + declareVariable("single_nested_enum", CelProtoTypes.INT64); source = "single_nested_enum == TestAllTypes.NestedEnum.BAR"; runTest(ImmutableMap.of("single_nested_enum", nestedEnum.getSingleNestedEnumValue())); @@ -692,15 +710,15 @@ public void nestedEnums() { @Test public void globalEnums() { - declareVariable("x", CelTypes.INT64); + declareVariable("x", CelProtoTypes.INT64); source = "x == dev.cel.testing.testdata.proto3.StandaloneGlobalEnum.SGAR"; runTest(ImmutableMap.of("x", StandaloneGlobalEnum.SGAR.getNumber())); } @Test public void lists() throws Exception { - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); - declareVariable("y", CelTypes.INT64); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("y", CelProtoTypes.INT64); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "([1, 2, 3] + x.repeated_int32)[3] == 4"; runTest(ImmutableMap.of("x", TestAllTypes.newBuilder().addRepeatedInt32(4).build())); @@ -717,7 +735,7 @@ public void lists() throws Exception { source = "!(4 in [1, 2, 3]) && 1 in [1, 2, 3]"; runTest(); - declareVariable("list", CelTypes.createList(CelTypes.INT64)); + declareVariable("list", CelProtoTypes.createList(CelProtoTypes.INT64)); source = "!(4 in list) && 1 in list"; runTest(ImmutableMap.of("list", ImmutableList.of(1L, 2L, 3L))); @@ -734,7 +752,7 @@ public void lists() throws Exception { @Test public void maps() throws Exception { - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); container = TestAllTypes.getDescriptor().getFile().getPackage(); source = "{1: 2, 3: 4}[3] == 4"; runTest(); @@ -754,8 +772,8 @@ public void maps() throws Exception { + ".oneof_type.payload.map_int32_int64[22] == 23"; runTest(ImmutableMap.of("x", TestAllTypes.newBuilder().putMapInt32Int64(22, 23).build())); - declareVariable("y", CelTypes.INT64); - declareVariable("map", CelTypes.createMap(CelTypes.INT64, CelTypes.INT64)); + declareVariable("y", CelProtoTypes.INT64); + declareVariable("map", CelProtoTypes.createMap(CelProtoTypes.INT64, CelProtoTypes.INT64)); // Constant key in variable map. source = "!(4 in map) && 1 in map"; @@ -778,7 +796,7 @@ public void maps() throws Exception { runTest(); // Repeated key - expressions - declareVariable("b", CelTypes.BOOL); + declareVariable("b", CelProtoTypes.BOOL); source = "{b: 1, !b: 2, b: 3}[true]"; runTest(ImmutableMap.of("b", true)); } @@ -797,7 +815,7 @@ public void comprehension() throws Exception { @Test public void abstractType() { - Type typeParam = CelTypes.createTypeParam("T"); + Type typeParam = CelProtoTypes.createTypeParam("T"); Type abstractType = Type.newBuilder() .setAbstractType( @@ -808,7 +826,7 @@ public void abstractType() { "vector", globalOverload( "vector", - ImmutableList.of(CelTypes.createList(typeParam)), + ImmutableList.of(CelProtoTypes.createList(typeParam)), ImmutableList.of("T"), abstractType)); // Declare a function to access element of a vector. @@ -816,7 +834,7 @@ public void abstractType() { "at", memberOverload( "at", - ImmutableList.of(abstractType, CelTypes.INT64), + ImmutableList.of(abstractType, CelProtoTypes.INT64), ImmutableList.of("T"), typeParam)); // Add function bindings for above @@ -847,13 +865,14 @@ public void abstractType() { public void namespacedFunctions() { declareFunction( "ns.func", - globalOverload("ns_func_overload", ImmutableList.of(CelTypes.STRING), CelTypes.INT64)); + globalOverload( + "ns_func_overload", ImmutableList.of(CelProtoTypes.STRING), CelProtoTypes.INT64)); declareFunction( "member", memberOverload( "ns_member_overload", - ImmutableList.of(CelTypes.INT64, CelTypes.INT64), - CelTypes.INT64)); + ImmutableList.of(CelProtoTypes.INT64, CelProtoTypes.INT64), + CelProtoTypes.INT64)); addFunctionBinding( CelFunctionBinding.from("ns_func_overload", String.class, s -> (long) s.length()), CelFunctionBinding.from("ns_member_overload", Long.class, Long.class, Long::sum)); @@ -893,12 +912,12 @@ public void namespacedFunctions() { @Test public void namespacedVariables() { container = "ns"; - declareVariable("ns.x", CelTypes.INT64); + declareVariable("ns.x", CelProtoTypes.INT64); source = "x"; runTest(ImmutableMap.of("ns.x", 2)); container = "dev.cel.testing.testdata.proto3"; - Type messageType = CelTypes.createMessage("google.api.expr.test.v1.proto3.TestAllTypes"); + Type messageType = CelProtoTypes.createMessage("cel.expr.conformance.proto3.TestAllTypes"); declareVariable("dev.cel.testing.testdata.proto3.msgVar", messageType); source = "msgVar.single_int32"; runTest( @@ -909,7 +928,7 @@ public void namespacedVariables() { @Test public void durationFunctions() { - declareVariable("d1", CelTypes.DURATION); + declareVariable("d1", CelProtoTypes.DURATION); Duration d1 = Duration.newBuilder().setSeconds(25 * 3600 + 59 * 60 + 1).setNanos(11000000).build(); Duration d2 = @@ -932,7 +951,7 @@ public void durationFunctions() { runTest(ImmutableMap.of("d1", d1)); runTest(ImmutableMap.of("d1", d2)); - declareVariable("val", CelTypes.INT64); + declareVariable("val", CelProtoTypes.INT64); source = "d1.getHours() < val"; runTest(extend(ImmutableMap.of("d1", d1), ImmutableMap.of("val", 30L))); source = "d1.getMinutes() > val"; @@ -945,7 +964,7 @@ public void durationFunctions() { @Test public void timestampFunctions() { - declareVariable("ts1", CelTypes.TIMESTAMP); + declareVariable("ts1", CelProtoTypes.TIMESTAMP); container = Type.getDescriptor().getFile().getPackage(); Timestamp ts1 = Timestamp.newBuilder().setSeconds(1).setNanos(11000000).build(); Timestamp ts2 = Timestamps.fromSeconds(-1); @@ -1050,7 +1069,7 @@ public void timestampFunctions() { source = "ts1.getMilliseconds(\"-8:00\")"; runTest(ImmutableMap.of("ts1", ts1)); - declareVariable("val", CelTypes.INT64); + declareVariable("val", CelProtoTypes.INT64); source = "ts1.getFullYear() < val"; runTest(extend(ImmutableMap.of("ts1", ts1), ImmutableMap.of("val", 2013L))); source = "ts1.getMonth() < val"; @@ -1076,7 +1095,7 @@ public void timestampFunctions() { @Test public void unknownField() { container = TestAllTypes.getDescriptor().getFile().getPackage(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); // Unknown field is accessed. source = "x.single_int32"; @@ -1108,7 +1127,7 @@ public void unknownField() { @Test public void unknownResultSet() { container = TestAllTypes.getDescriptor().getFile().getPackage(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); TestAllTypes message = TestAllTypes.newBuilder() .setSingleString("test") @@ -1185,7 +1204,9 @@ public void unknownResultSet() { // dispatch test declareFunction( - "f", memberOverload("f", Arrays.asList(CelTypes.INT64, CelTypes.INT64), CelTypes.BOOL)); + "f", + memberOverload( + "f", Arrays.asList(CelProtoTypes.INT64, CelProtoTypes.INT64), CelProtoTypes.BOOL)); addFunctionBinding(CelFunctionBinding.from("f", Integer.class, Integer.class, Objects::equals)); // dispatch: unknown.f(1) ==> unknown @@ -1206,8 +1227,7 @@ public void unknownResultSet() { // ident is unknown ==> unknown source = "x"; - ExprValue unknownMessage = - ExprValue.newBuilder().setUnknown(UnknownSet.getDefaultInstance()).build(); + CelUnknownSet unknownMessage = CelUnknownSet.create(1L); runTest(ImmutableMap.of("x", unknownMessage)); // comprehension test @@ -1298,12 +1318,20 @@ 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 public void timeConversions() { container = Type.getDescriptor().getFile().getPackage(); - declareVariable("t1", CelTypes.TIMESTAMP); + declareVariable("t1", CelProtoTypes.TIMESTAMP); source = "timestamp(\"1972-01-01T10:00:20.021-05:00\")"; runTest(); @@ -1334,8 +1362,8 @@ public void timeConversions() { @Test public void sizeTests() { container = Type.getDescriptor().getFile().getPackage(); - declareVariable("str", CelTypes.STRING); - declareVariable("b", CelTypes.BYTES); + declareVariable("str", CelProtoTypes.STRING); + declareVariable("b", CelProtoTypes.BYTES); source = "size(b) == 5 && b.size() == 5"; runTest(ImmutableMap.of("b", ByteString.copyFromUtf8("happy"))); @@ -1360,7 +1388,7 @@ public void nonstrictQuantifierTests() { source = "![0, 2, 4].all(x, 4/x != 2 && 4/(4-x) != 2)"; runTest(); - declareVariable("four", CelTypes.INT64); + declareVariable("four", CelProtoTypes.INT64); // Condition is dynamic. source = "[0, 2, 4].exists(x, four/x == 2 && four/(four-x) == 2)"; @@ -1430,7 +1458,7 @@ public void regexpMatchingTests() { runTest(); // Constant string. - declareVariable("regexp", CelTypes.STRING); + declareVariable("regexp", CelProtoTypes.STRING); source = "matches(\"alpha\", regexp) == true"; runTest(ImmutableMap.of("regexp", "^al.*")); @@ -1458,7 +1486,7 @@ public void regexpMatchingTests() { runTest(ImmutableMap.of("regexp", ".*ha.$")); // Constant regexp. - declareVariable("s", CelTypes.STRING); + declareVariable("s", CelProtoTypes.STRING); source = "matches(s, \"^al.*\") == true"; runTest(ImmutableMap.of("s", "alpha")); @@ -1680,7 +1708,7 @@ public void dyn_error() { @Test public void jsonValueTypes() { container = TestAllTypes.getDescriptor().getFile().getPackage(); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); // JSON bool selection. TestAllTypes xBool = @@ -1762,7 +1790,10 @@ public void jsonValueTypes() { // Ensure that types are being wrapped and unwrapped on function dispatch. declareFunction( "pair", - globalOverload("pair", ImmutableList.of(CelTypes.STRING, CelTypes.STRING), CelTypes.DYN)); + globalOverload( + "pair", + ImmutableList.of(CelProtoTypes.STRING, CelProtoTypes.STRING), + CelProtoTypes.DYN)); addFunctionBinding( CelFunctionBinding.from( "pair", @@ -1782,8 +1813,8 @@ public void jsonValueTypes() { @Test public void jsonConversions() { - declareVariable("ts", CelTypes.TIMESTAMP); - declareVariable("du", CelTypes.DURATION); + declareVariable("ts", CelProtoTypes.TIMESTAMP); + declareVariable("du", CelProtoTypes.DURATION); source = "google.protobuf.Struct { fields: {'timestamp': ts, 'duration': du } }"; runTest(ImmutableMap.of("ts", Timestamps.fromSeconds(100), "du", Durations.fromMillis(200))); } @@ -1820,14 +1851,14 @@ public void typeComparisons() { source = "type(TestAllTypes{}) == TestAllTypes && " + "type(TestAllTypes{}) == proto3.TestAllTypes && " - + "type(TestAllTypes{}) == .google.api.expr.test.v1.proto3.TestAllTypes && " + + "type(TestAllTypes{}) == .cel.expr.conformance.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"; + + "type(proto3.TestAllTypes{}) == .cel.expr.conformance.proto3.TestAllTypes && " + + "type(.cel.expr.conformance.proto3.TestAllTypes{}) == TestAllTypes && " + + "type(.cel.expr.conformance.proto3.TestAllTypes{}) == proto3.TestAllTypes && " + + "type(.cel.expr.conformance.proto3.TestAllTypes{}) == " + + ".cel.expr.conformance.proto3.TestAllTypes"; runTest(); // Test whether a type name is recognized as a type. @@ -1857,7 +1888,7 @@ public void wrappers() throws Exception { .setSingleUint32Wrapper(UInt32Value.of(12)) .setSingleUint64Wrapper(UInt64Value.of(34)); - declareVariable("x", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("x", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "x.single_bool_wrapper == true && " + "x.single_bytes_wrapper == b'hi' && " @@ -1909,12 +1940,12 @@ public void longComprehension() { declareFunction( "constantLongList", globalOverload( - "constantLongList", ImmutableList.of(), CelTypes.createList(CelTypes.INT64))); + "constantLongList", ImmutableList.of(), CelProtoTypes.createList(CelProtoTypes.INT64))); source = "size(constantLongList().map(x, x+1)) == 1000"; runTest(); // Comprehension over long list that is not compile-time constant. - declareVariable("longlist", CelTypes.createList(CelTypes.INT64)); + declareVariable("longlist", CelProtoTypes.createList(CelProtoTypes.INT64)); source = "size(longlist.map(x, x+1)) == 1000"; runTest(ImmutableMap.of("longlist", l)); @@ -1927,14 +1958,14 @@ public void longComprehension() { CelFunctionBinding.from("f_unleash", Object.class, x -> x)); declareFunction( "f_slow_inc", - globalOverload("f_slow_inc", ImmutableList.of(CelTypes.INT64), CelTypes.INT64)); + globalOverload("f_slow_inc", ImmutableList.of(CelProtoTypes.INT64), CelProtoTypes.INT64)); declareFunction( "f_unleash", globalOverload( "f_unleash", - ImmutableList.of(CelTypes.createTypeParam("A")), + ImmutableList.of(CelProtoTypes.createTypeParam("A")), ImmutableList.of("A"), - CelTypes.createTypeParam("A"))); + CelProtoTypes.createTypeParam("A"))); source = "f_unleash(longlist.map(x, f_slow_inc(x)))[0] == 1"; runTest(ImmutableMap.of("longlist", l)); } @@ -1942,7 +1973,7 @@ public void longComprehension() { @Test public void maxComprehension() { // Comprehension over long list that is not compile-time constant. - declareVariable("longlist", CelTypes.createList(CelTypes.INT64)); + declareVariable("longlist", CelProtoTypes.createList(CelProtoTypes.INT64)); source = "size(longlist.map(x, x+1)) == 1000"; // Comprehension which exceeds the configured iteration limit. @@ -2006,7 +2037,7 @@ public void dynamicMessage_adapted() throws Exception { wrapperBindings.toByteArray(), DefaultDescriptorPool.INSTANCE.getExtensionRegistry())); - declareVariable("msg", CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable("msg", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "msg.single_any"; assertThat(runTest(input)).isInstanceOf(NestedMessage.class); @@ -2110,22 +2141,24 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { // Test any unpacking // With well-known type Any anyDuration = Any.pack(Durations.fromSeconds(100)); - declareVariable("dur", CelTypes.TIMESTAMP); + declareVariable("dur", CelProtoTypes.TIMESTAMP); source = "TestAllTypes { single_any: dur }.single_any"; 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())); + "any_packed_test_msg", + CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); source = "TestAllTypes { single_any: any_packed_test_msg }.single_any"; assertThat(runTest(ImmutableMap.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())); + "test_msg", CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())); + declareVariable( + "dynamic_msg", CelProtoTypes.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); @@ -2144,13 +2177,14 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { "f_msg", globalOverload( "f_msg_generated", - ImmutableList.of(CelTypes.createMessage(TestAllTypes.getDescriptor().getFullName())), - CelTypes.BOOL), + ImmutableList.of( + CelProtoTypes.createMessage(TestAllTypes.getDescriptor().getFullName())), + CelProtoTypes.BOOL), globalOverload( "f_msg_dynamic", ImmutableList.of( - CelTypes.createMessage(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFullName())), - CelTypes.BOOL)); + CelProtoTypes.createMessage(TEST_ALL_TYPE_DYNAMIC_DESCRIPTOR.getFullName())), + CelProtoTypes.BOOL)); addFunctionBinding( CelFunctionBinding.from("f_msg_generated", TestAllTypes.class, x -> true), CelFunctionBinding.from("f_msg_dynamic", DynamicMessage.class, x -> true)); @@ -2165,6 +2199,40 @@ public void dynamicMessage_dynamicDescriptor() throws Exception { assertThat(runTest(input)).isInstanceOf(Boolean.class); } + @Immutable + private static final class RecordedValues { + @SuppressWarnings("Immutable") + private final Map recordedValues = new HashMap<>(); + + @CanIgnoreReturnValue + public Object record(String key, Object value) { + recordedValues.put(key, value); + return value; + } + + public ImmutableMap getRecordedValues() { + return ImmutableMap.copyOf(recordedValues); + } + } + + @Test + public void lateBoundFunctions() throws Exception { + RecordedValues recordedValues = new RecordedValues(); + CelLateFunctionBindings lateBindings = + CelLateFunctionBindings.from( + CelFunctionBinding.from( + "record_string_dyn", String.class, Object.class, recordedValues::record)); + declareFunction( + "record", + globalOverload( + "record_string_dyn", + ImmutableList.of(CelProtoTypes.STRING, CelProtoTypes.DYN), + CelProtoTypes.DYN)); + source = "record('foo', 'bar')"; + assertThat(runTest(ImmutableMap.of(), lateBindings)).isEqualTo("bar"); + assertThat(recordedValues.getRecordedValues()).containsExactly("foo", "bar"); + } + /** * Checks that the CheckedExpr produced by CelCompiler is equal to the one reproduced by the * native CelAbstractSyntaxTree diff --git a/testing/src/main/java/dev/cel/testing/CelBaselineTestCase.java b/testing/src/main/java/dev/cel/testing/CelBaselineTestCase.java index ca48de469..04d6a3c58 100644 --- a/testing/src/main/java/dev/cel/testing/CelBaselineTestCase.java +++ b/testing/src/main/java/dev/cel/testing/CelBaselineTestCase.java @@ -28,6 +28,7 @@ import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; import dev.cel.common.CelValidationException; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; import dev.cel.common.types.CelTypeProvider; import dev.cel.common.types.CelTypes; @@ -56,8 +57,8 @@ public abstract class CelBaselineTestCase extends BaselineTestCase { protected static final CelOptions TEST_OPTIONS = CelOptions.current() .enableTimestampEpoch(true) - .enableUnsignedLongs(true) .enableHeterogeneousNumericComparisons(true) + .enableHiddenAccumulatorVar(true) .enableOptionalSyntax(true) .comprehensionMaxIterations(1_000) .build(); @@ -208,7 +209,8 @@ protected String formatDecl(String name, List declarations) { private void formatDeclImpl(Decl decl, StringBuilder declStr) { switch (decl.getDeclKindCase()) { case IDENT: - declStr.append(String.format(" value %s%n", CelTypes.format(decl.getIdent().getType()))); + declStr.append( + String.format(" value %s%n", CelProtoTypes.format(decl.getIdent().getType()))); break; case FUNCTION: for (Overload overload : decl.getFunction().getOverloadsList()) { @@ -217,9 +219,9 @@ private void formatDeclImpl(Decl decl, StringBuilder declStr) { " function %s %s%n", overload.getOverloadId(), CelTypes.formatFunction( - CelTypes.typeToCelType(overload.getResultType()), + CelProtoTypes.typeToCelType(overload.getResultType()), overload.getParamsList().stream() - .map(CelTypes::typeToCelType) + .map(CelProtoTypes::typeToCelType) .collect(toImmutableList()), overload.getIsInstanceFunction(), /* typeParamToDyn= */ false))); diff --git a/testing/src/main/java/dev/cel/testing/TestCelVariableDeclWrapper.java b/testing/src/main/java/dev/cel/testing/TestCelVariableDeclWrapper.java index 20c2c4843..2cb94f87b 100644 --- a/testing/src/main/java/dev/cel/testing/TestCelVariableDeclWrapper.java +++ b/testing/src/main/java/dev/cel/testing/TestCelVariableDeclWrapper.java @@ -17,8 +17,8 @@ import dev.cel.expr.Decl; import dev.cel.expr.Decl.IdentDecl; import dev.cel.expr.Type; +import dev.cel.common.types.CelProtoTypes; import dev.cel.common.types.CelType; -import dev.cel.common.types.CelTypes; import dev.cel.compiler.CelCompilerBuilder; /** Wrapper for CEL native type based variable declarations */ @@ -33,7 +33,7 @@ class TestCelVariableDeclWrapper extends TestDecl { @Override void loadDeclsToCompiler(CelCompilerBuilder compiler) { - CelType celType = CelTypes.typeToCelType(type); + CelType celType = CelProtoTypes.typeToCelType(type); compiler.addVar(name, celType); } 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; + } }